当使用内部有嵌套条件的 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。
最佳答案
In my experience, the ReSharper way will loop two times: one to generate the filtered IEnumerable, and after to loop the results of the .Where query again.
不会,它只会循环一次。 Where
不会循环您的集合 - 它只会创建用于枚举您的集合的迭代器。下面是 LINQ 解决方案的样子:
using(var iterator = listOfRadioButtons.Where(rb => rb.IsChecked == true))
{
while(iterator.MoveNext())
{
RadioButton item = iterator.Current;
// something
}
}
您的原始代码在性能方面更好 - 您将避免创建委托(delegate)并将其传递给 WhereEnumerableIterator
的实例,然后为源序列中的每个项目执行委托(delegate)。但是您应该注意,正如@dcastro 指出的那样,差异将非常小并且在您必须优化此特定循环之前不值得一提。
ReSharper 建议的解决方案(可能)更利于可读性。我个人喜欢循环中的简单 if
条件。
更新:Where
迭代器可以简化为(也省略了一些接口(interface))
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()
,它将枚举源序列并返回所有匹配项,这些项将保存到新列表中。
关于c# - 以 ReSharper 方式使用嵌套条件循环有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21406528/