簡體   English   中英

泛型列表 <List<T> &gt;

[英]Generics List<List<T>>

如果我有List<T> ,它從MyClass類型中得到了一些列表,例如List<List<MyClass>>MyClassMyClassB的父類。 為什么我不能執行以下操作?

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對象。

如果更改代碼,使myListList<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>();

您需要告訴編譯器,我認為MyClass是MyClassB的父級。 這篇有關where關鍵字的文章可能會進一步幫助您

即使MyClassB是MyClass的子類型,也並不意味着List是List的子類型。 您要問的問題是為什么List與T不協變(這將導致List成為List的子類型,其中T是Y的子類型。請查找協方差和對數。

答案有兩個。 首先,在C#實施協和反方差之前先實施List。 但最重要的是,僅當T為“輸出”類型時才可以協變。 由於您可以將內容推入列表,因此它不是out類型。 IEnumerable僅發出類型為T的對象。因此,它可以是協變的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM