以ReSharper方式循环使用嵌套条件有什么好处?

Gui*_*rme 1 c# wpf resharper foreach loops

当使用带有嵌套条件的foreach循环时,我用以下方式编写:

foreach (RadioButton item in listOfRadioButtons)
{
    if (item.IsChecked == true)
    {
         // sometging
    }
}
Run Code Online (Sandbox Code Playgroud)

但我已经安装了ReSharper,它建议将此循环更改为以下形式(删除if并使用lambda):

foreach (RadioButton item in listOfRadioButtons.Where(item => item.IsChecked == true))
{
    // something
}
Run Code Online (Sandbox Code Playgroud)

根据我的经验,ReSharper方式将循环两次:一次生成过滤的IEnumerable,然后再循环.Where查询的结果.

我是对的?如果是这样,为什么ReSharper建议这样做?因为在我看来,第一个也更可靠.

注意:WPF RadioButton的默认IsChecked属性是Nullable bool,因此需要在条件内使用== true,.Value或强制转换为bool才能返回bool.

Ser*_*kiy 5

根据我的经验,ReSharper方式将循环两次:一次生成过滤的IEnumerable,然后再循环.Where查询的结果.

不,它只会循环一次.Where不循环您的集合 - 它只创建将用于枚举您的集合的迭代器.以下是LINQ解决方案的样子:

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

您的原始代码更适合性能 - 您将避免创建委托并将其传递给实例WhereEnumerableIterator,然后为源序列中的每个项执行委托.但你应该注意,正如@dcastro指出的那样,差异将非常小,并且在您必须优化此特定循环之前不值得注意.

ReSharper建议的解决方案(可能)更易于阅读.我个人喜欢if循环中的简单条件.

更新: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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的主要想法 - 只有当你要求它移动到下一个项目时它才会枚举原始来源.然后迭代器转到原始源中的下一个项目并检查它是否与谓词匹配.如果找到匹配,则返回当前项并将枚举源置于保持状态.

因此,在您不会询问此迭代器中的项目之前,它不会枚举源代码.如果您将调用ToList()此迭代器,它将枚举源序列并返回所有匹配的项目,这些项目将保存到新列表中.