Linq: порядок выполнения цепного запроса
Я хочу понять, как обрабатывается цепной запрос. Например, рассмотрим следующий запрос
var sumOfRoots = numbers //IEnum0
.Where(x => x > 0) //IEnum1
.Select(x => Math.Sqrt(x)) //IEnum2
.Select(x => Math.Exp(x)) //IEnum3
.Sum();
Где, например, numbers={-1, 4, 9 }.
Вот что происходит за сценой:
1. Получение всех перечислителей (прямой проход)
-
numbersвызываетGetEnumerator(), который возвращает (обозначим его)IEnum0экземпляр -
IEnum0вызываетGetEnumerator(), который возвращаетIEnum1экземпляр -
IEnum1вызываетGetEnumerator(), который возвращаетIEnum2экземпляр -
IEnum2вызываетGetEnumerator(), который возвращаетIEnum3экземпляр
2. Вызов MoveNext (обратный проход)
-
.Sum()вызываетMoveNext()наIEnum3 -
IEnum3вызываетMoveNext()наIEnum2 -
IEnum2вызываетMoveNext()наIEnum1 -
IEnum1вызываетMoveNext()наIEnum0
3. Возврат из MoveNext (прямой-обратный проход)
-
IEnum0переходит к элементу-1и возвращаетtrue. -
IEnum1проверьте, если-1удовлетворяют условию (которое не истинно), поэтомуIEnum1вызываетMoveNext()наIEnum0. -
IEnum0переходит к элементу4и возвращаетtrue. -
IEnum1Проверьте, удовлетворяет ли4условию (которое истинно) и возвращаетtrue -
IEnum2ничего не делает, просто возвращает выводIEnum1, который являетсяtrue -
IEnum2ничего не делает, просто возвращает выводIEnum2, который являетсяtrue
4. Вызов тока (обратный проход)
-
.Sum()вызываетCurrentнаIEnum3. -
IEnum3вызываетCurrentнаIEnum2 -
IEnum2вызываетCurrentнаIEnum1 -
IEnum1вызываетCurrentнаIEnum0
5. Обратный ток (прямой проход)
-
IEnum0возвращает4 -
IEnum1возвращает4 -
IEnum2возвращаетsqrt(4)=2 -
IEnum3возвращаетexp(2)
6. Повторите шаги 2.-5. до шага 3. возвращает false
Пожалуйста, поправьте меня, если цепной запрос обрабатывается в различный способ.
1 ответ:
Вы можете использовать делегатов для понимания порядка выполнения. Пример:
static void Main(string[] args) { var numbers = new []{ -1, 4, 9 }; double sumOfRoots = numbers.Where(IsGreaterThanZero) .Select(ToSquareRoot) .Select(ToExp) .Sum(x => ToNumber(x)); Console.WriteLine($"sumOfRoots = {sumOfRoots}"); Console.Read(); } private static double ToNumber(double number) { Console.WriteLine($"SumNumber({number})"); return number; } private static double ToSquareRoot(int number) { double value = Math.Sqrt(number); Console.WriteLine($"Math.Sqrt({number}): {value}"); return value; } private static double ToExp(double number) { double value = Math.Exp(number); Console.WriteLine($"Math.Exp({number}): {value}"); return value; } private static bool IsGreaterThanZero(int number) { bool isGreater = number > 0; Console.WriteLine($"{number} > 0: {isGreater}"); return isGreater; }Вывод:
-1 > 0: False
4 > 0: True
Математика.Sqrt(4): 2
Математика.Exp (2): 7.38905609893065
SumNumber(7.38905609893065)
9 > 0: True
Математика.Sqrt (9): 3
Математика.Exp (3): 20.0855369231877
SumNumber(20.0855369231877)
SumOfRoots = 27,4745930221183