2014-01-28 34 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