[英]Generics List<List<T>>
如果我有List<T>
,它從MyClass
類型中得到了一些列表,例如List<List<MyClass>>
和MyClass
是MyClassB
的父類。 為什么我不能執行以下操作?
List<List<MyClass>> allLists = new List<List<MyClass>>();
List<MyClassB> myList = new List<MyClassB>();
myList.Add(new MyClassB());
//And now the point which dont work
allLists.Add(myList);
如果我實現一個方法,我可以說SomeClass<T> ... where T : MyClass
,列表問題是否有類似的東西?
這樣我可以將任何子類的列表添加到我的第一級列表中?
class Animal {}
class Tiger : Animal {}
class Giraffe : Animal {}
...
List<Giraffe> giraffes = new List<Giraffe>();
List<List<Animal>> lists = new List<List<Animal>>();
lists.Add(giraffes); // Illegal!
您的問題是“為什么這是違法的?” 答案是:假設這是合法的,那就繼續吧...
List<Animal> animals = lists[0]; // Obviously typesafe.
animals.Add(new Tiger()); // Obviously typesafe
我們只是將老虎添加到了長頸鹿列表中。
由於后面兩個步驟顯然是類型安全的,因此不能類型安全的地方必須是Add(giraffes)
。
現在,從C#4開始,它確實起作用:
List<IEnumerable<Animal>> lists = new List<IEnumerable<Animal>>();
lists.Add(giraffes);
為什么那是合法的? 因為IEnumerable<T>
上沒有Add
方法:
IEnumerable<Animal> animals = lists[0];
現在我們不能違反類型安全性,因為如果僅通過IEnumerable<T>
訪問它,就無法將老虎放入該長頸鹿列表。
順便說一句,幾乎每天都有人問這個問題。 在網絡上搜索“ C#協方差和逆方差”,您將獲得有關它的更多信息。
您無法執行此操作的原因如下:假設allLists.Add(myList)
有效。 然后,編譯器將知道allLists[0]
是List<MyClass>
,因此allLists[0]
以下條件:
allLists[0].Add(new MyClassX());
那將是一個運行時錯誤,因為allLists[0]
實際上是List<MyClassB>
。 它不能容納MyClassX
對象。
如果更改代碼,使myList
為List<MyClass>
,則代碼將起作用:
List<MyClass> myList = new List<MyClass>();
myList.Add(new MyClassB()); // This works, because MyClassB extends MyClass
allLists.Add(myList); // This works, too
您必須使用允許派生類的接口(稱為協變接口 )作為內部集合:
var allLists = new List<IEnumerable<MyClass>>();
List<List<MyClass>> allLists = new List<List<MyClass>>();
您要添加的列表不是同一類型。 您可能會這樣:
interface IMyClass
{
//some properties
}
您的所有子類都必須繼承自IMyClass。 然后,您將獲得像這樣的列表。
List<List<IMyClass>> allLists = new List<List<IMyClass>>();
問題是AllLists是強類型的,以包含MyClass的列表。 MyList是強類型的,以包含MyClassB的實例。
盡管您可以將List存儲在List>中,但是當前代碼中的類型不匹配。
這將解決問題:
List<MyClass> myList = new List<MyClass>();
即使MyClassB是MyClass的子類型,也並不意味着List是List的子類型。 您要問的問題是為什么List與T不協變(這將導致List成為List的子類型,其中T是Y的子類型。請查找協方差和對數。
答案有兩個。 首先,在C#實施協和反方差之前先實施List。 但最重要的是,僅當T為“輸出”類型時才可以協變。 由於您可以將內容推入列表,因此它不是out類型。 IEnumerable僅發出類型為T的對象。因此,它可以是協變的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.