2011-09-09 127 views
1

如果我有兩類:將類型的泛型容器強制轉換爲繼承類型的容器?

public class A { } 
public class B : A { } 

和我創建一個通用的容器,而這需要它的功能:

public void Foo(List<A> lst) { ... } 

我得到一個無效的轉換,如果我試圖鑄造List<B>List<A>,而是必須通過它,像這樣:

var derivedList = new List<B>(); 
Foo(new List<A>(derivedList)); 

是否有某種方式來傳遞一個List<B>這函數沒有分配全新列表的開銷,或者C#不支持從派生類型的泛型容器轉換爲其基類型?

+0

請參閱此處:http://stackoverflow.com/questions/1817300/convert-list-of-derived-class-objects-to-list-of-base-class-objects – SwDevMan81

+0

相關:http:// stackoverflow。 com/questions/686305 /轉換成一個基類型的繼承類型列表 – SwDevMan81

回答

4

一個List<B>根本不是一個List<A> - 畢竟,你可以添加一個普通AList<A>,而不是一個List<B>

如果您正在使用C#4和.NET 4 你的Foo方法只真正需要遍歷列表,然後更改方法:

public void Foo(IEnumerable<A> lst) { ... } 

在.NET 4中,IEnumerable<T>covariant in T,其允許從IEnumerable<B>(包括List<B>)到IEnumerable<A>的轉換。這是安全的,因爲價值只會流出IEnumerable<A>

想要更詳細地瞭解這一點,您可以觀看我在NDC 2010上給出的作爲torrent of NDC 2010 videos的一部分的會話視頻。

1

這是不可能的。 C#不支持在具體類型(如List<T>)上進行共同/反對差異。它不支持它的接口雖然如此,如果你切換Foo下面簽名就可以避免分配

public void Foo(IEnumerable<A> enumerable) { ... 
+0

IList <>沒有工作,但IEnumerable <>做了。 – Michael

0

如果你想通過列表類似的東西例程這要讀他們,但沒有寫他們,將有可能定義通用協變IReadableList接口,以便可以將IReadableList <Cat>傳遞給期望IReadableList的例程<Animal>。不幸的是,現有的IList實現不會實現任何這樣的事情,因此實現它的唯一方法是實現一個包裝類(它可以接受IList作爲參數),但它可能不會太難。這樣的類還應該實現非泛型IList,也是隻讀的,以允許代碼評估計數,而不必知道列表中項目的類型。

請注意,IReadableList對象的實現不應被視爲任何不可變性的承諾。由於讀寫列表是可讀,因此讀寫列表或包裝類實現IReadableList <T>將是完全合理的。無法使用IReadableList <T>來修改列表而不將其轉換爲其他內容,但不能保證列表已通過,因爲IReadableList <T>無法以其他方式修改,例如將其轉換爲其他方式或者通過使用存儲在別處的參考。