【问题标题】:Any benefit to loop with nested condition in the ReSharper way?以 ReSharper 方式循环嵌套条件有什么好处?
【发布时间】:2014-02-19 19:21:41
【问题描述】:

当使用内部有嵌套条件的 foreach 循环时,我曾经这样写:

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

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

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

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

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

注意:WPF RadioButton 的默认 IsChecked 属性是 Nullable bool,因此它需要一个 == true、一个 .Value 或在条件内强制转换为 bool 以返回 bool。

【问题讨论】:

  • 很明显,JetBrains 知道一些你不知道的事情。
  • ReSharper 建议使用item.IsChecked == true 不是很好
  • 为什么不呢? IsChecked 是一个布尔值?,而不是一个布尔值
  • 最好将这一事实添加到您的问题中。

标签: c# wpf loops foreach resharper


【解决方案1】:

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

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

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

您的原始代码在性能方面更好 - 您将避免创建委托并将其传递给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();
    }
}

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

因此,除非您不会从该迭代器中询问项目,否则它不会枚举源。如果你在这个迭代器上调用ToList(),它将枚举源序列并返回所有匹配的项目,这些项目将被保存到新的列表中。

【讨论】:

  • 这行得通吗?使用 if 条件则不会,因为它是一个可为空的布尔值并且可以返回空值。要删除 == true,我建议使用“if (item.IsChecked.Value)”
  • @Guilherme 不知道IsCheckedNullable&lt;bool&gt;。那么是的,与true 比较是不错的选择
  • "您的原始代码性能更好。"我想对此进行扩展。性能影响几乎不明显。两种解决方案仍将在线性 O(n) 时间内运行。但是,使用 Where 您会从迭代器的额外抽象层中获得轻微的性能影响。
  • @SergeyBerezovskiy 谢谢你的例子
  • @dcastro 同意你的观点,我只是指出性能会有差异。而且它会非常小,过早的优化是一个大恶 :)
猜你喜欢
  • 1970-01-01
  • 2010-10-14
  • 2013-08-09
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多