Останавливает ли LINQ для объектов обработку Any (), если условие истинно? - PullRequest
14 голосов
/ 21 марта 2011

Рассмотрим следующее:

bool invalidChildren = this.Children.Any(c => !c.IsValid());

Этот класс имеет коллекцию дочерних объектов, у которых есть метод IsValid(). Предположим, что метод IsValid() требует много ресурсов процессора. После обнаружения первого дочернего объекта, где IsValid() равен false, теоретически обработка может быть остановлена, поскольку результат никогда не станет истинным. Останавливает ли LINQ для объектов фактически оценку после первого IsValid() = false (как логическое И) или продолжает вычислять все дочерние объекты?

Очевидно, я мог бы просто поместить это в цикл foreach и разбить первый недопустимый результат, но мне было просто интересно, достаточно ли умна LINQ для объектов, чтобы делать это тоже.

EDIT: Спасибо за ответы, по какой-то причине я не думал сам искать его на MSDN.

Ответы [ 5 ]

21 голосов
/ 21 марта 2011

Да, это так. Как только он находит соответствие, критерии утверждаются. All аналогичен тем, что проверяет все элементы, но если один из них не совпадает, он также немедленно завершается.

Exists работает так же.

Любой

Перечисление источника останавливается, как только может быть определен результат.

* Exists 1016 *

Элементы текущего списка индивидуально передаются делегату Predicate, и обработка останавливается, когда найдено совпадение.

Все

Перечисление источника останавливается, как только может быть определен результат.

и т.д ...

6 голосов
/ 21 марта 2011

Да, он останавливается, как только результаты могут быть оценены.Вот быстрое доказательство:

class Program
    {
        static void Main(string[] args)
        {
            bool allvalid = TestClasses().Any(t => !t.IsValid());
            Console.ReadLine();
        }

        public static IEnumerable<TestClass> TestClasses()
        {
            yield return new TestClass() { IsValid = () => { Console.Write(string.Format("TRUE{0}",Environment.NewLine)); return true; } };
            yield return new TestClass() { IsValid = () => { Console.Write(string.Format("FALSE{0}", Environment.NewLine)); return false; } };
            yield return new TestClass() { IsValid = () => { Console.Write(string.Format("TRUE{0}", Environment.NewLine)); return true; } };
            yield return new TestClass() { IsValid = () => { Console.Write(string.Format("TRUE{0}", Environment.NewLine)); return true; } };
        }
    }

    public class TestClass
    {
        public Func<bool> IsValid {get;set;}
    }
2 голосов
/ 21 марта 2011

Да, он остановится после того, как встретит первый элемент, для которого соответствует условие, в вашем случае первый элемент, для которого c.IsValid() возвращает false.

С MSDN :

Перечисление источника остановлено как только результат может быть определены.

1 голос
/ 21 марта 2011

Вот быстрый и грязный эмпирический тест, чтобы убедиться в этом:

class Kebab
{
    public static int NumberOfCallsToIsValid = 0;

    public bool IsValid()
    {
        NumberOfCallsToIsValid++;
        return false;
    }
}

...

var kebabs = new Kebab[] { new Kebab(), new Kebab() };
kebabs.Any(kebab => !kebab.IsValid());

Debug.Assert(Kebab.NumberOfCallsToIsValid == 1);

В результате да, оператор Any LINQ останавливается, как только элемент коллекции соответствует предикату.

1 голос
/ 21 марта 2011

согласно MSDN,

Перечисление source останавливается, как только может быть определен результат.

...