c# - list差異 - list to ienumerable




IEnumerable vs List-使用什麼? 他們如何工作? (6)

IEnumerable的優點是延遲執行(通常使用數據庫)。 在實際循環數據之前,查詢不會被執行。 這是一個等待直到需要的查詢(又稱延遲加載)。

如果你打電話給ToList,查詢將會被執行,或者像我想說的那樣“物化”。

兩者都有優點和缺點。 如果你打電話給ToList,你可能會刪除一些關於何時執行查詢的秘密。 如果你堅持IEnumerable,你會得到這樣的好處:程序在實際需要之前不會做任何工作。

我對Enumerators如何工作以及LINQ有一些疑問。 考慮這兩個簡單的選擇:

List<Animal> sel = (from animal in Animals 
                    join race in Species
                    on animal.SpeciesKey equals race.SpeciesKey
                    select animal).Distinct().ToList();

要么

IEnumerable<Animal> sel = (from animal in Animals 
                           join race in Species
                           on animal.SpeciesKey equals race.SpeciesKey
                           select animal).Distinct();

我改變了我的原始對象的名字,這樣看起來就像一個更通用的例子。 查詢本身並不重要。 我想問的是這樣的:

foreach (Animal animal in sel) { /*do stuff*/ }
  1. 我注意到,如果我使用IEnumerable ,當我調試和檢查“sel”時,它是IEnumerable,它有一些有趣的成員:“inner”,“outer”,“innerKeySelector”和“outerKeySelector”,最後2似乎是代表。 “內部”成員中沒有“Animal”實例,而是“Species”實例,這對我來說很奇怪。 “外層”成員確實包含“動物”實例。 我認為這兩位代表決定進入哪些內容?

  2. 我注意到如果我使用“Distinct”,“inner”包含6個項目(這是不正確的,因為只有2個是Distinct),但是“outer”包含正確的值。 同樣,委託方法可能決定了這一點,但這比我對IEnumerable的了解還多一點。

  3. 最重要的是,兩種選擇中的哪一種選擇是最好的表現?

通過.ToList()邪惡的列表轉換?

或者可能直接使用枚舉器?

如果可以的話,也請解釋一下或者拋出一些解釋IEnumerable的使用的鏈接。


IEnumerable描述了行為,而List則是該行為的實現。 當你使用IEnumerable ,你給編譯器一個延遲工作的機會,直到後來才有可能優化。 如果使用ToList(),則可以強制編譯器立即生成結果。

無論何時“堆疊”LINQ表達式,我都使用IEnumerable ,因為通過只指定行為,我給了LINQ一個延遲評估和可能優化程序的機會。 記住LINQ在枚舉之前不會生成SQL來查詢數據庫? 考慮這個:

public IEnumerable<Animals> AllSpotted()
{
    return from a in Zoo.Animals
           where a.coat.HasSpots == true
           select a;
}

public IEnumerable<Animals> Feline(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Felidae"
           select a;
}

public IEnumerable<Animals> Canine(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Canidae"
           select a;
}

現在你有一個方法可以選擇一個初始樣本(“AllSpotted”)和一些過濾器。 所以現在你可以做到這一點:

var Leopards = Feline(AllSpotted());
var Hyenas = Canine(AllSpotted());

那麼在IEnumerable上使用List會更快嗎? 僅當您想要阻止多次執行查詢時。 但是總體來說更好嗎? 那麼在上面,Leopards和Hyenas 每個都被轉換成單個SQL查詢 ,而數據庫只返回相關的行。 但是如果我們從AllSpotted()返回一個List,那麼它可能會運行得更慢,因為數據庫可能會返回比實際需要更多的數據,並且我們會浪費循環在客戶端進行過濾。

在一個程序中,最好延遲將查詢轉換為列表直到最後,所以如果我要不止一次地通過Leopards和Hyenas枚舉,我會這樣做:

List<Animals> Leopards = Feline(AllSpotted()).ToList();
List<Animals> Hyenas = Canine(AllSpotted()).ToList();

實現IEnumerable的類允許您使用foreach語法。

基本上它有一種方法來獲取集合中的下一個項目。 它不需要整個集合在內存中,也不需要知道其中有多少物品, foreach只是不斷得到下一個物品,直到它耗盡。

在某些情況下,這可能非常有用,例如,在開始處理行之前,您不想將整個事件複製到內存中的海量數據庫表中。

現在List實現IEnumerable ,但代表了內存中的整個集合。 如果你有一個IEnumerable並且調用.ToList()你可以在內存中創建一個枚舉內容的新列表。

你的linq表達式返回一個枚舉,默認情況下,當你使用foreach迭代時,表達式會執行。 迭代foreach時會執行IEnumerable linq語句,但您可以使用.ToList()更快地強制迭代。

這就是我的意思:

var things = 
    from item in BigDatabaseCall()
    where ....
    select item;

// this will iterate through the entire linq statement:
int count = things.Count();

// this will stop after iterating the first one, but will execute the linq again
bool hasAnyRecs = things.Any();

// this will execute the linq statement *again*
foreach( var thing in things ) ...

// this will copy the results to a list in memory
var list = things.ToList()

// this won't iterate through again, the list knows how many items are in it
int count2 = list.Count();

// this won't execute the linq statement - we have it copied to the list
foreach( var thing in list ) ...

我將分享一個我陷入一天的誤用概念:

var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"};

var startingWith_M = names.Where(x => x.StartsWith("m"));

var startingWith_F = names.Where(x => x.StartsWith("f"));


// updating existing list
names[0] = "ford";

// Guess what should be printed before continuing
print( startingWith_M.ToList() );
print( startingWith_F.ToList() );

預期結果

// I was expecting    
print( startingWith_M.ToList() ); // mercedes, mazda
print( startingWith_F.ToList() ); // fiat, ferrari

實際結果

// what printed actualy   
print( startingWith_M.ToList() ); // mercedes
print( startingWith_F.ToList() ); // ford, fiat, ferrari

說明

根據其他答案,對結果的評估被推遲到調用ToList或類似的調用方法,例如ToArray

所以我可以在這種情況下重寫代碼:

var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"};

// updating existing list
names[0] = "ford";

// before calling ToList directly
var startingWith_M = names.Where(x => x.StartsWith("m"));

var startingWith_F = names.Where(x => x.StartsWith("f"));

print( startingWith_M.ToList() );
print( startingWith_F.ToList() );

周圍玩

https://repl.it/E8Ki/0


沒有人提到一個關鍵的區別,諷刺地回答了一個關於這個重複的問題。

IEnumerable是只讀的,List不是。

請參閱List和IEnumerable的實際區別


要認識到的最重要的事情是,使用Linq,查詢不會立即得到評估。 它只是作為遍歷所產生的IEnumerable<T>一部分來運行 - 這就是所有奇怪的代表正在做的事情。

因此,第一個示例通過調用ToList並將查詢結果放入列表中來立即評估查詢。
第二個示例返回一個IEnumerable<T> ,其中包含稍後運行查詢所需的所有信息。

在性能方面,答案取決於 。 如果您需要一次對結果進行評估(例如,您正在改變稍後查詢的結構,或者如果您不希望通過IEnumerable<T>進行迭代需要很長時間),請使用列表。 否則使用IEnumerable<T> 。 默認情況下應該使用第二個示例中的按需評估,因為通常使用較少的內存,除非有特定的理由將結果存儲在列表中。





ienumerable