【问题标题】:How to convert a generic List<T> to an Interface based List<T>如何将通用 List<T> 转换为基于接口的 List<T>
【发布时间】:2011-01-17 08:47:15
【问题描述】:

我确定我遗漏了一些简单的东西,但是我正在尝试将所有实现接口的对象的强类型列表转换为该接口类型的列表。

下面是一个演示错误的示例:

public void ExampleCode(){
    List<Cube> cubes = new List<Cube>();
    List<Shape> allShapes;
    allShapes = cubes;//Syntax Error
    allShapes = (List<Shape>)cubes;//Syntax Error  
}

public class Cube : Shape
{
    public int ID { get; set; }
    public int Sides { get; set; }
}

public interface Shape
{
  int ID { get; set; }
  int Sides { get; set; }
}

【问题讨论】:

  • 注意:问题中的代码被表述为演员表(即同一对象的不同视图)。下面给出的不同解决方法复制列表 - 创建一个新列表并将每个 Shape 元素添加到新列表中 - 给出不同的对象,而不是同一对象的不同视图。

标签: c# .net generics interface type-conversion


【解决方案1】:

不要像那样投射,试试:

allShapes = cubes.Cast<Shape>().ToList();

为此,您需要 .NET 3.5。我相信可以在 System.Linq 中找到 Cast 扩展方法。

【讨论】:

  • 注意,这会复制列表(尽管如果它包含引用引用而不是对象将被复制)。这与转换列表对象本身不同。
  • 这与您在 .NET 3.5 中所能获得的一样接近。无法按要求转换列表对象。
【解决方案2】:

你不能。因为List&lt;T&gt;ILIst&lt;T&gt; 只支持不变类型参数。这归结为T 同时用于输入和输出参数(例如返回值)。否则你可能会破坏类型安全。

其他接口(例如IEntumerable&lt;T&gt;)确实允许一些差异。

请参阅 Eric Lippert 的博客“Fabulous Adventures In Coding”,了解对方差和协方差的讨论。特别是“Covariance and Contravariance”标签。

编辑,刚刚添加到“C#常见问题”博客:Covariance and Contravariance FAQ

【讨论】:

    【解决方案3】:

    您所指的内容称为泛型协方差,c# 3 不支持它。但是,c# 4 (.NET 4 / VS 2010) 支持它,您可以在此处阅读更多信息:

    Variance in Generic Interfaces

    话虽如此,IList&lt;T&gt; 不是协变的(因为它既接受又公开T)。另一方面,IEnumerable&lt;T&gt; 是协变的(因为它不接受 T)。

    【讨论】:

      【解决方案4】:

      您不能这样做,因为通过这种方式转换可能会失去所有类型安全性。例如,将List&lt;Shape&gt; 转换为List&lt;object&gt; 将导致any 类型的对象可以添加到列表中,这将是完全不一致的。

      【讨论】:

        【解决方案5】:

        你也可以这样做:

        allShapes = cubes.ConvertAll(x => (Shape)x);
        

        或者,如果您在 .NET 2.0 中执行此操作:

        allShapes = cubes.ConvertAll<Shape>(delegate(Cube c){
            return (Shape)c;
        });
        

        【讨论】:

          【解决方案6】:

          您不能在类型列表之间进行转换,即使类型本身是可转换的。您将需要创建一个新列表并填充它,方法是迭代原始列表或使用 ConvertAll。示例代码见http://www.dev102.com/2008/05/15/how-to-convert-listt1-to-listt2/

          【讨论】:

            【解决方案7】:

            如果您将 allShapes 定义为 IEnumerable,则此方法有效

            在 C# 4.0 中,您可以简单地分配 allshapes=cubes

            对于 C# 3.5,您可以使用 allShapes = cubes.Select(c=>((Shape)c));

            但无论如何你都需要使用 IEnumerable 而不是 List

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-11-26
              • 2019-04-13
              • 1970-01-01
              • 2019-05-20
              • 2014-02-05
              • 2012-02-24
              • 1970-01-01
              相关资源
              最近更新 更多