簡體   English   中英

LINQ Where語句中的條件是否會在循環期間重新評估?

[英]Will the condition on a LINQ Where-statement re-evaluate during the loop?

我有這個foreach -loop:

foreach (var classId in m_ClassMappings[taAddressDefinition.Key])
{
    if(!m_TAAddressDefinitions.ContainsKey(classId))
    {
        m_TAAddressDefinitions.Add(classId, taAddressDefinition.Value);
    }
}

m_TAAddressDefinitions是一個IDictionary ,其中classId用作唯一的Key值。
Resharper建議將if -statement更改為LINQ過濾器,如下所示:

foreach (var classId in m_ClassMappings[taAddressDefinition.Key].Where(
    classId => !m_TAAddressDefinitions.ContainsKey(classId)))
{
    m_TAAddressDefinitions.Add(classId, taAddressDefinition.Value);
}

如果這可能無法按預期工作,我感到很遺憾,因為m_TAAddressDefinitions集合的內容在循環內部發生了變化,這導致LINQ過濾條件的源( classId => !m_TAAddressDefinitions.ContainsKey(classId) )在辦法。

如果在循環內添加了兩個具有相同值的classId ,或者在將值添加到集合時是否重新計算LINQ條件,這會失敗嗎? 如果密鑰已經存在,我原來的if語句意圖不會導致異常。

在這種情況下,重構版本中Where返回的IEnumerable會在迭代時懶散地生成值,從而實現您想要的效果。 包含的建議ToList調用不是你想在這種情況下,有什么,因為這將兌現的IEnumerable一個集合,你會容易有被復制classIdsm_ClassMappings集合。

需要記住的是, Where調用中的謂詞,即classId => !m_TAAddressDefinitions.ContainsKey(classId)將在每個項目中作為迭代IEnumerable的結果進行評估。 因此,在Resharper建議的版本中,如果m_ClassMappings存在重復值,則m_ClassMappings的第一個值將被添加到m_TAAddressDefinitions但是當到達下一個副本時, Where謂詞將返回false,因為該值先前已添加到Dictionary中。

建議的更改不會改變邏輯。 lambda表達式classId => !m_TAAddressDefinitions.ContainsKey(classId)將被編譯成一個匿名類,您的字典將被傳入。由於這是一個引用而不是它的副本,對字典的更改將反映在評估中。

這個概念被稱為閉包 有關更深入的信息,請參閱Jon Skeet的回答: .NET中的“閉包”是什么? 他的帖子The Beauty of Closures是一個非常代碼閱讀。

你不修改m_ClassMappingsm_TAAddressDefinitions ,所以CollectionModifiedException暫不上調。

更好地重寫它

m_ClassMappings[taAddressDefinition.Key]
  .Where(classId => !m_TAAddressDefinitions.ContainsKey(classId)))  
  .ToList()
  .ForEach(
    classId => m_TAAddressDefinitions.Add(classId, taAddressDefinition.Value)); 

暫無
暫無

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

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