【问题标题】:Cast List<T> to List<Interface>将 List<T> 转换为 List<Interface>
【发布时间】:2012-02-14 01:45:48
【问题描述】:
public interface IDic
{
    int Id { get; set; }
    string Name { get; set; }
}
public class Client : IDic
{

}

如何将List&lt;Client&gt; 转换为List&lt;IDic&gt;

【问题讨论】:

    标签: c# .net interface casting


    【解决方案1】:

    你不能 cast 它(保留参考身份)——那是不安全的。例如:

    public interface IFruit {}
    
    public class Apple : IFruit {}
    public class Banana : IFruit {}
    
    ...
    
    List<Apple> apples = new List<Apple>();
    List<IFruit> fruit = apples; // Fortunately not allowed
    fruit.Add(new Banana());
    
    // Eek - it's a banana!
    Apple apple = apples[0];
    

    现在,由于协方差,您可以在 .NET 4 / C# 4 中将 List&lt;Apple&gt; 转换为 IEnumerable&lt;IFruit&gt;,但如果您想要 List&lt;IFruit&gt;,则必须创建一个 new列表。例如:

    // In .NET 4, using the covariance of IEnumerable<T>
    List<IFruit> fruit = apples.ToList<IFruit>();
    
    // In .NET 3.5
    List<IFruit> fruit = apples.Cast<IFruit>().ToList();
    

    但这与投射原始列表相同 - 因为现在有两个单独的列表。这是安全的,但您需要了解对一个列表所做的更改不会在另一列表中看到。 (当然会看到对列表引用的对象的修改。)

    【讨论】:

    • 就像他们'还在大楼里'!
    • 做协方差tolist和做new List有什么区别();然后对原始列表进行 foreach 并将每个项目添加到 IFruit 列表中?在 foreach 方式中......对象引用将是相同的,对吗?所以......如果这是真的,我个人认为你不能直接投出整个名单是没有意义的。 ?
    • @RobertNoack:“对象引用”是什么意思?每个 element 的对象引用是相同的,但这与转换列表引用本身不同。假设您可以强制转换引用,因此您有一个编译时类型List&lt;IFruit&gt; 的引用,它实际上是对List&lt;Apple&gt; 的引用。如果您将 Banana 引用添加到该 List&lt;IFruit&gt;,您期望会发生什么?
    • @TrươngQuốcKhánh:我不知道您的代码的 any 是什么样的,或者您是否有针对 System.Linqusing 指令,或者您正在尝试什么调用它,我不确定您希望我如何提供帮助。我建议你做更多的研究,如果你仍然卡住,你可以通过minimal reproducible example 提问。
    • @JamesJoyce:“但为什么不反过来呢?”正是因为这就是您最终添加香蕉的方式-如果您可以执行该任务。您认为List&lt;IFruit&gt; fruit = apples; fruit.Add(new Banana()); 中的哪个语句不起作用?
    【解决方案2】:

    Cast 迭代器和 .ToList():

    List&lt;IDic&gt; casted = input.Cast&lt;IDic&gt;().ToList() 可以解决问题。

    最初我说协方差会起作用 - 但正如 Jon 正确指出的那样;不,不会!

    原来我也愚蠢地放弃了ToList() 电话

    【讨论】:

    • Cast 返回 IEnumerable&lt;T&gt;,而不是 List&lt;T&gt; - 不,协方差 不会 允许这种转换,因为它不安全 - 请参阅我的回答.
    • 从您链接到的页面:“只有接口类型和委托类型可以有变体类型参数”
    • @Jon - 在阅读您的评论之前,我已经意识到 ToList() 丢失了;但是是的,正如您所展示的,协方差当然不起作用!哇!
    • 对。协方差仍然可以提供帮助,因为这意味着您不需要 .NET 4 中的 Cast 调用,只要您将类型参数指定为 ToList
    【解决方案3】:

    我也遇到了这个问题,在阅读 Jon Skeet 的回答后,我将代码从使用 List&lt;T&gt; 修改为使用 IEnumerable&lt;T&gt;。虽然这不能回答 OP 的原始问题 我如何将 List&lt;Client&gt; 转换为 List&lt;IDic&gt;,但它确实避免了这样做的需要,因此可能对遇到此问题的其他人有所帮助。这当然假设需要使用List&lt;IDic&gt; 的代码在您的控制之下。

    例如:

    public void ProcessIDic(IEnumerable<IDic> sequence)
    {
       // Implementation
    }
    

    代替:

    public void ProcessIDic(List<IDic> list)
    {
       // Implementation
    }
    

    【讨论】:

      【解决方案4】:

      如果您可以使用 LINQ,那么您可以这样做...

      List<Client> clientList = new List<Client>();
      List<IDic> list = clientList.Select(c => (IDic)c).ToList();
      

      【讨论】:

        【解决方案5】:
        List<Client> listOfA = new List<Client>();
        List<IDic> list = listOfA.Cast<IDic>().ToList();
        

        【讨论】:

          【解决方案6】:

          只有通过创建新的List&lt;IDic&gt; 并转移所有元素才能实现。

          【讨论】:

          • 任何评论为什么不赞成,因为一般含义与所有其他答案相同?
          • 我的猜测是你被否决了,因为你说只能创建一个新列表,但其他人却发表了相反的看法……虽然不是我的否决)
          • 好吧,他们确实创建了新列表,但没有使用 new 运算符,这并没有改变他们所做的事实。
          【解决方案7】:

          在 .Net 3.5 中,您可以执行以下操作:

          List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());
          

          在这种情况下,List 的构造函数采用 IEnumerable。
          list 虽然只能转换为 IEnumerable。即使 myObj 可以转换为 ISomeInterface 类型 IEnumerable 也不能转换为 IEnumerable。

          【讨论】:

          • 问题是这会复制列表,大多数时候你想对原始列表进行操作
          【解决方案8】:

          OfType

          你可以试试这样的:

                  using (var dbContext = YourDatabaseContext())
                  {
                      var list = dbContext.Clients.Where(x => x.Happy)
                          .OfType<IDic>()
                          .ToList();
                  }
          

          https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.oftype

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-11-26
            • 2019-05-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多