2008-11-24 52 views
13

我與LINQ合作對象,並有一個函數,其中在某些情況下,我需要調用Aggregate(...)之前修改底層集合,然後返回到原來的狀態在函數返回Aggregate(...)的結果之前。我當前的代碼看起來是這樣的:東西比.ToArray()更好的給力LINQ輸出的枚舉

bool collectionModified = false; 
if(collectionNeedsModification) 
{ 
    modifyCollection(); 
    collectionModified = true; 
} 

var aggregationResult = from a in 
          (from b in collection 
          where b.SatisfysCondition) 
          .Aggregate(aggregationFunction) 
         select a.NeededValue; 

if(collectionModified) 
    modifyCollection(); 

return aggregationResult; 

然而,正如寫的,如果我修改集合,我會得到錯誤的結果,因爲我把收集回來的原始狀態之前aggregationResult枚舉和LINQ結果是懶惰評估。我目前的解決辦法是在我的LINQ查詢中使用.ToArray()這樣的:

var aggregationResult = (from a in 
          (from b in collection 
          where b.SatisfysCondition) 
          .Aggregate(aggregationFunction) 
         select a.NeededValue).ToArray(); 

結果數組的大小永遠是小(< 100項),這樣存儲/處理時間是不是一個問題。這是處理我的問題的最佳方式,還是有更好的方法來強制評估LINQ查詢?

回答

15

只是爲了檢查我瞭解你 - 你基本上要通過所有的結果進行迭代,只是爲了強迫任何副作用的發生?

副作用通常是一個壞主意,正是因爲東西是很難用這樣的邏輯來理解。話雖如此,要做到這一點,迫使充分評估的最簡單的方法可能是隻是遍歷它:

foreach (var result in aggregationResult) 
{ 
    // Deliberately empty; simply forcing evaluation of the sequence. 
} 

另外,您可以使用LastOrDefault()避免()參與ToArray的所有拷貝。 Count()只要結果不執行IList<T>(涉及捷徑)就可以。

+2

我更喜歡'.LastOrDefault()`。請注意,`LastOrDefault`也是一個捷徑(在我的版本中,.NET 4.5.2)。如果源是一個`IList <>`,它將首先獲得`Count`,然後使用索引器獲取索引爲'Count-1`的元素。例如這個工程(使用Moq):`var listMock = new Mock >(MockBehavior.Strict); listMock.Setup(x => x.Count).Returns(666); listMock.Setup(x => x [665])。返回(「last one」); var last = listMock.Object.LastOrDefault();` – 2014-12-05 12:31:05

0

我不認爲這是你的方法,如果你經常使用的結果(因爲你的結果集並不大,它會不會消耗多少內存的問題。順便說一句,如果你做到這一點,從不使用結果,它會造成性能損失)。 所以,是的,這是做到這一點的正確方法。

3

這是更好地避免像上面modifyCollection副作用的功能。

一個更好的方法是使返回修改後的集合(或查詢),讓最初的一個完整的功能。

var modifiedCollection = ModifyCollection(collection, collectionNeedsModification); 

var aggregationResult = from a in 
         (from b in modifiedCollection 
         where b.SatisfysCondition) 
         .Aggregate(aggregationFunction) 
        select a.NeededValue; 

哪裏ModifyCollection的是,在根據collectionNeedsModification布爾參數的參數返回修改的集合(或查詢)的方法。

12

(注:輸入而手頭編譯器,所以代碼是未經測試)

如果您有.NET無擴展爲一個依賴已經可以使用運行():

aggregationResult.Run(); 

但它可能不值得爲此添加依賴項。

您也可以自己實現Run方法作爲擴展方法:

public static MyLinqExtensions 
{ 
    public static void Run<T>(this IEnumerable<T> e) 
    { 
     foreach (var _ in e); 
    } 
} 
+0

當枚舉數可能是'alive'(如在RX中)或好的時候,這可能是個好問題。但是,當我們需要確保收集不是懶惰時,我不認爲這是一般用途,我認爲`LastOrDefault` - 這需要快捷方式 - 更好。 – 2016-09-01 10:11:19