【问题标题】:How do i convert a List<Interface> to List<Class> in c#如何在 c# 中将 List<Interface> 转换为 List<Class>
【发布时间】:2017-06-21 07:03:16
【问题描述】:

我有一个接口定义为

public interface IReaderInfo
{
    string Displayname {get;}
}

以及实现该接口的类

public class ReaderInfo : IReaderInfo
{
    string DisplayName {get;}
}

然后我创建了一个返回列表的函数

public List<ReaderInfo> GetReaders
{
     var readers = new List<ReaderInfo>();
     var Ireaders = someobject.Getreaders();// Returns the list of IReaderInfo.
     // Now i would like cast Ireaders as readers and return.
}

我该如何施放它?

【问题讨论】:

  • 如果您需要将IReaderInfo 转换为ReaderInfo 那么为什么要使用接口
  • 当你有接口时返回一个具体类的列表有什么意义?你打算如何处理实现接口但 不是 ReaderInfo 的对象?为什么不返回List&lt;IReaderInfo&gt;

标签: c# oop casting


【解决方案1】:

您必须创建一个包含已投射项目的新列表:

var readers = Ireaders.Cast<ReaderInfo>().ToList();

或者,如果存在不兼容的 IReaderInfo 条目并且您只希望结果中包含实际的 ReaderInfo 对象:

var readers = Ireaders.OfType<ReaderInfo>().ToList();

【讨论】:

  • 如果元素不是实际上 ReaderInfo 实例,这将失败。任何类都可以实现这个接口
  • @RaviKumarGN 那么当你得到一个不是 ReaderInfo 的对象时会发生什么?当您尝试使用模拟 IReaderInfo 对象测试此代码时会发生什么?如果GetReaders 返回 ReaderInfo 对象怎么办?它明确告诉您它不会只返回 ReaderInfo。使用 CastOfType 会破坏 API
  • @PanagiotisKanavos 不会考虑 OfType 建议吗?决定是否需要不同的实际类型以及如何处理它们不是我或您的责任 - 但我认为使用Cast(抛出不同类型)和OfType(过滤不同类型)的可能性主要是覆盖。
  • @grek40 没有什么可以决定的。方法保证明确声明它将返回仅具有特定接口的对象。其他任何事情都是不安全的假设
  • @PanagiotisKanavos 这仅适用于someobject.Getreaders,但GetReaders 可以有不同的合同,这只是定义和文档的问题,以指定调用方法并且数据不同时会发生什么超出预期。
【解决方案2】:

快速且非常肮脏的解决方法是使用OfType<> 仅传递实际上 ReaderInfo 的对象。如果任何对象实现IReaderInfo 而实际上成为 ReaderInfo

,则使用Cast<> 将失败
var Ireaders = someobject.Getreaders();
var readers=Ireaders.OfType<ReaderInfo>().ToList();
return readers;

但更好的解决方案是更改方法的签名以返回List&lt;IReaderInfo&gt;,或更抽象的IList&lt;IReaderInfo&gt;。如果GetReaders 返回一个接口列表,则意味着它可以返回实现该接口的任何 对象。

为什么要丢弃一些?当所有对象都实现相同的接口时,为什么GetReaders 决定使用哪些对象以及丢弃哪些对象?

public IList<IReaderInfo> GetReaders
{
    var readers = new List<ReaderInfo>();
    var Ireaders = someobject.Getreaders();// Returns the list of IReaderInfo.
    return Ireaders;
}

例如,当方法确实打算返回不同的类型(例如模拟对象或处理多个实现)时,它们通常会返回接口。通过返回List&lt;ReaderInfo&gt;,您可以防止您的方法处理有效对象

更新

版本控制是另一个非常重要的原因,为什么一个不应该将接口转换为具体类型。

谷歌搜索 IReaderInfo 我发现了几页提到 RFID 阅读器。 ReaderInfo 返回阅读器的功能,但您如何为新阅读器公开 功能?

在不破坏兼容性的情况下公开新功能的常用方法是引入实现旧接口IReaderInfo 的新类,并通过新接口(例如IReaderInfo2)放置公开新功能。或者 existing 类可以用IReaderInfo2 扩展。库可以做到这一点,因为客户端只能通过接口工作,而不是直接针对具体类。

【讨论】:

  • 如果客户端只能通过接口工作,那么为什么要公开这个类呢?如果没有公共类,库的任何用户都不会遇到从接口转换到类的整个问题。
  • @grek40 出于同样的原因,BCL 中的许多方法都公开了接口而不是具体的类。版本控制只是一种情况。可测试性是另一个问题 - BCL 团队最大的遗憾之一是对类的硬编码超出了应有的程度
【解决方案3】:

使用 LINQ:

Ireaders.Cast<ReaderInfo>().ToList();

【讨论】:

  • Ireaders.OfType&lt;ReaderInfo&gt;().Cast&lt;ReaderInfo&gt;().ToList() 应该满足所有 cmets。
  • 有时,当源集合中有意外项时,最好在 Cast 中抛出异常,而不是使用 OfType 默默地忽略它。这取决于上下文和要求/规格,作者没有具体说明细节,所以我的回答只是关于铸造。
【解决方案4】:

通过使用 Linq

var derivedList = Ireaders.Cast<ReaderInfo>();

【讨论】:

  • 如果任何对象实现了接口但 不是 实际的 IReaderInfo
  • 抛出异常不是一个好主意,这就是这段代码的作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 2021-08-05
  • 2013-09-21
  • 1970-01-01
相关资源
最近更新 更多