2014-01-28 35 views
1

當使用內部嵌套條件的foreach循環,我曾經寫在下面的方法:以ReSharper方式循環嵌套條件的好處是什麼?

foreach (RadioButton item in listOfRadioButtons) 
{ 
    if (item.IsChecked == true) 
    { 
     // sometging 
    } 
} 

但我已經安裝了ReSharper並提出要改變這種循環以下形式(移除如果和使用Lambda):

foreach (RadioButton item in listOfRadioButtons.Where(item => item.IsChecked == true)) 
{ 
    // something 
} 

以我的經驗,ReSharper的方式將循環兩次:一個生成過濾的IEnumerable,並循環後再次的。哪裏查詢的結果。

我說得對嗎?如果是這樣,爲什麼ReSharper暗示這一點?因爲在我看來,第一個也更可靠。

注意:WPF RadioButton的默認IsChecked屬性是一個Nullable bool,所以它需要一個== true,.Value或者一個強制轉換來返回bool。

+1

顯然,JetBrains知道你不知道的東西。 –

+2

http://stackoverflow.com/questions/9072126/linq-foreach-vs-foreach-if :) –

+2

ReSharper不是很好,如果它建議使用'item.IsChecked == true' –

回答

5

以我的經驗,ReSharper的方式將循環兩次:一個以 生成過濾的IEnumerable,並循環 的。凡查詢結果後再次。

不,它只會循環一次。 Where不會循環您的集合 - 它只會創建將用於枚舉集合的迭代器。這裏是LINQ解決方案的樣子:

using(var iterator = listOfRadioButtons.Where(rb => rb.IsChecked == true)) 
{ 
    while(iterator.MoveNext()) 
    { 
     RadioButton item = iterator.Current; 
     // something 
    } 
} 

您的原始代碼是獲得更好的性能 - 你會避免創建委派,並將其傳遞給實例的WhereEnumerableIterator,然後在源序列的每個項目執行代表。但是你應該注意,正如@dcastro所指出的,差異將會非常小,不值得注意,直到你必須優化這個特定的循環。

ReSharper建議的解決方案是(可能)更好的可讀性。我個人喜歡簡單的if條件循環。

UPDATE:Where迭代器可以簡化爲(也有一些接口被省略)

public class WhereEnumerableIterator<T> : IEnumerable<T>, IDisposable 
{ 
    private IEnumerator<T> _enumerator; 
    private Func<T,bool> _predicate; 

    public WhereEnumerableIterator(IEnumerable<T> source, Func<T,bool> predicate) 
    { 
     _predicate = predicate; 
     _enumerator = source.GetEnumerator(); 
    } 

    public bool MoveNext() 
    { 
     while (_enumerator.MoveNext()) 
     { 
      if (_predicate(_enumerator.Current)) 
      { 
       Current = _enumerator.Current; 
       return true; 
      } 
     } 

     return false; 
    } 

    public T Current { get; private set; } 

    public void Dispose() 
    { 
     if (_enumerator != null) 
      _enumerator.Dispose(); 
    } 
} 

主要思想在這裏 - 它列舉只有當你向它移動到下一個項目原始來源。然後迭代器轉到原始源中的下一個項目,並檢查它是否與謂詞匹配。如果找到匹配項,則它返回當前項並將枚舉源置於保持狀態。

所以,直到你不會問這個迭代器的項目,它不會枚舉源。如果你在這個迭代器上調用ToList(),它將枚舉源序列並返回所有匹配的項目,這些項目將被保存到新列表中。

+0

這工作?如果if條件不成立,因爲它是一個可空的bool,可以返回null。要刪除== true,我會推薦「if(item.IsChecked.Value)」 – Guilherme

+0

@Guilherme不知道'IsChecked'是一個'可空的'。那麼是的,與'true'的比較是很好的選擇 –

+1

「您的原始代碼對性能更好。」我想對此進行擴展。性能影響*幾乎不明顯。兩種解決方案仍將以線性O(n)時間運行。但是,使用'Where'可以從迭代器的額外抽象層獲得*輕微*的性能。 – dcastro