2010-02-16 19 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的任何情況下

相關問題