繁体   English   中英

Enumerable.Any() 和可能的多个枚举

[英]Enumerable.Any() and possible multiple enumerations

Rider/ReSharper 给了我可能的多重枚举警告:

public void ProcessProductCodes(IEnumerable<string> productCodes) {
    if (productCodes.Any()) {
        DoStuff(productCodes);
    }
}

是误报,还是 Any() function 确实弄乱了集合的枚举?

IEnumerable接口表示可以迭代的项目序列,但不对序列的来源做任何假设。 例如,它可以是数据库查询。 如果是这种情况,您将对数据库进行 2 次调用,一次用于检查序列中是否有任何项目,另一次用于将它们传递给DoStuff function,这显然不是最佳性能,而 ReSharper 是警告你这一点。

为避免此问题,您有 2 种不同的选择。 如果项目集合已经在 memory 中,您可以通过将 function 的签名更改为:

public void ProcessProductCodes(ICollection<string> productCodes) { ... }

如果您不能保证这一点,您可以在 function 的开头执行.ToList().ToArray

public void ProcessProductCodes(IEnumerable<string> productCodes) {
  var productCodesList = productCodes.ToList();
  if (productCodesList .Any()) {
      DoStuff(productCodesList );
  }

ReSharper 将为您执行此操作,只需 select 快速重构(通常使用Alt+Enter )。

您可以创建一个辅助方法(我已将其创建为扩展方法)以确保它只迭代一次:

public static class LinqExtensions
{
    public static bool DoIfAny<T>(this IEnumerable<T> collection, Action<IEnumerable<T>> action)
    {
        var enumerator = collection.GetEnumerator();
        if (!enumerator.MoveNext())
        {
            return false;
        }

        action(CreateEnumerableFromStartedEnumerable(enumerator));
        return true;
    }

    private static IEnumerable<T> CreateEnumerableFromStartedEnumerable<T>(IEnumerator<T> enumerator)
    {
        do
        {
            yield return enumerator.Current;
        }
        while (enumerator.MoveNext());
    }
}

本质上,这将为集合创建一个枚举器,然后尝试移动到第一项。 如果失败,则不调用该方法并返回false

如果它成功,那么它将产生一个新的枚举,它迭代源枚举的 rest,并在运行时产生它的值。 这包括第一个值。 然后将其传递给操作委托并返回true

用法:

IEnumerable<string> values = new string[] { "a", "b", "c" };
bool delegateCalled = values.DoIfAny(e => DoStuff(e));
Console.WriteLine("Delegate called: " + delegateCalled.ToString());

在线尝试

请注意,只有在“集合不为空”的意义上想要.Any()时,这才会真正起作用。 如果它正在检查特定元素的存在,那么您必须首先将列表具体化,如 Tao 的回答。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM