如何将通用List <t>转换为基于接口的List <t> </t> </t>

时间:2010-02-16 11:29:14

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

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

以下是演示错误的示例:

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; }
}

7 个答案:

答案 0 :(得分:13)

请尝试:

,而不是像那样投射
allShapes = cubes.Cast<Shape>().ToList();

你需要.NET 3.5。我相信Cast扩展方法可以在System.Linq。

中找到

答案 1 :(得分:6)

你做不到。因为List<T>ILIst<T>仅支持不变类型参数。这低至T,用于输入和输出参数(例如返回值)。否则你可以打破类型安全。

其他界面(例如IEntumerable<T>)确实允许一些差异。

有关反对和协方差的讨论,请参阅Eric Lippert的博客“Fabulous Adventures In Coding”。特别是“Covariance and Contravariance”代码。

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

答案 2 :(得分:4)

您所指的是通用协方差,并且不受c#3支持。但是,它受到c#4(.NET 4 / VS 2010)的支持,您可以在此处阅读更多相关信息:

  

Variance in Generic Interfaces

话虽如此,IList<T>不是协变的(因为它既接受又暴露T)。另一方面,IEnumerable<T>是协变的(因为它不接受T)。

答案 3 :(得分:2)

你无法做到这一点,因为通过这种方式进行投射可能会失去所有类型的安全性。对于instnce,将List<Shape>转换为List<object>将导致任何类型的对象可以添加到列表中,这将完全不一致。

答案 4 :(得分:0)

你也可以这样做:

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

或者如果你在.NET 2.0中这样做:

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

如果将allShapes定义为IEnumerable

,则此方法有效

在C#4.0中,您可以简单地指定allshapes = cubes

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

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