2010-02-16 20 views
7

我确定我缺少一些简单的东西,但是我试图将所有实现接口的对象的强类型列表转换为该接口类型的列表。如何将通用列表<T>转换为基于接口的列表<T>

下面是证明错误示例:

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

NB:在讨论的代码被表述为一个铸件(同一物体的不同即视图)。下面给出的不同解决方法复制列表 - 创建一个新列表,并将每个Shape元素添加到新列表中 - 给出不同的对象,而不是同一对象上的不同视图。 – 2010-02-16 11:39:43

回答

13

相反铸造这样的尝试:

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

需要.NET 3.5的这一点。我相信Cast扩展方法可以在System.Linq中找到。

+1

你打败了我。 – Steven 2010-02-16 11:32:33

+2

请注意,这将复制列表(尽管它包含引用而不是对象将被复制)。这与转换列表对象本身并不相同。 – Richard 2010-02-16 11:35:41

+1

@理查德:好点。 – 2010-02-16 12:47:20

6

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

其他接口(例如IEntumerable<T>)确实允许有些差异。

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

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

2

你不能做到这一点,因为铸造这种方式,您有可能失去所有类型的安全性。就此而言,铸造List<Shape>List<object>将导致的任何类型的对象都可以添加到列表中,这将是彻头彻尾的不一致。

0

你也可以这样做:

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

或者,如果你在做这个.NET 2.0:

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

什么你指的是被称为通用的协方差和C#3.然而,由C#4(.NET 4/VS 2010)支持不支持,你可以在这里阅读更多关于它:

Variance in Generic Interfaces

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

0

如果你定义allShapes为IEnumerable

在C#4.0中,你可以简单地分配allshapes这工作=立方体

对于C#3.5,你可以使用allShapes =立方体。选择(C =>((形状)C));

但在需要使用而不是List IEnumerable的任何情况下

相关问题