使用 Select(...).Any(...) 时 select 的方法是 运行 多少次?

How many times select's method is run when using Select(...).Any(...)?

首先,我有这段代码,如果满足条件,它会中断第二个循环。

所以比如第一次满足条件,就不会枚举第二个循环的其他元素

foreach (var evaluator in strategyEvaluators)
{
   foreach (var rule in concatedRules)
   {
        var isEntryRuleMet = evaluator.Evaluate(rule.Code);

        if (isEntryRuleMet)
        {
           matchedNames.Add(evaluator.Name);
           break;
        }
   }
}

但是我也发现可以这样缩短代码:

foreach (var evaluator in strategyEvaluators)
{
   if (concatedRules.Select(rule=> evaluator.Evaluate(rule.Code)).Any(isEntryRuleMet => isEntryRuleMet))
   {
       matchedNames.Add(evaluator.Name);
   }
}

注意,对于第二种方式,我不知道Select方法会运行.

多少次

Select 是在 Any returns 之后立即停止吗?还是说完了运行ning然后Any就是运行?

Is Select stopped right after Any returns true? Or is it finished running and then Any is run?

是的,是的。你可以这样想:Select 产生元素到 Any 只要它 returns false,一旦它 returns true,它stops.Remaining 个元素未生成。

这是一个演示它的简单程序:

public static void Main()
{
    var query = Enumerable.Range(0,10).Select(x => GetNumber(x)).Any(x => x > 5);       
}


public static int GetNumber(int x)
{
    Console.WriteLine("GetNumber is called: {0}", x);
    return x;
}

// Output:

GetNumber is called: 0
GetNumber is called: 1
GetNumber is called: 2
GetNumber is called: 3
GetNumber is called: 4
GetNumber is called: 5
GetNumber is called: 6

Select满足Any后会停止运行。因此,一旦 Any returns 为真,它就会跳出 foreach 循环,不再具体化集合。

您甚至可能希望将代码编写为

foreach (var evaluator in strategyEvaluators)
{
   if (concatedRules.Any(rule=>evaluator.Evaluate(rule.Code)))
   {
       matchedNames.Add(evaluator.Name);
   }
}

这样你根本不用担心 select。

当第一个 Any 成功时迭代停止。

您甚至可以通过这样做使您的代码更小:

var matchedNames =
    strategyEvaluators
        .Where(evaluator =>
            concatedRules
                .Where(rule => evaluator.Evaluate(rule.Code))
                .Any())
        .Select(evaluator => evaluator.Name)
        .ToList();

如果 matchedNames 已经定义,那么试试这个:

matchedNames
    .AddRange(
        strategyEvaluators
            .Where(evaluator =>
                concatedRules
                    .Where(rule => evaluator.Evaluate(rule.Code))
                    .Any())
            .Select(evaluator => evaluator.Name));