简体   繁体   中英

Linq: Order of execution chain query

I want to understand how chain query is processed. For example, let us consider the following query

var sumOfRoots = numbers           //IEnum0
     .Where(x => x > 0)            //IEnum1
     .Select(x => Math.Sqrt(x))    //IEnum2
     .Select(x => Math.Exp(x))     //IEnum3
     .Sum();

where eg numbers={-1, 4, 9 }.

Is this what happends behind the scene:

1. Getting all enumerators (forward pass)

  • numbers calls GetEnumerator() which returns (let us denote it with) IEnum0 instance
  • IEnum0 calls GetEnumerator() which returns IEnum1 instance
  • IEnum1 calls GetEnumerator() which returns IEnum2 instance
  • IEnum2 calls GetEnumerator() which returns IEnum3 instance

2. Calling MoveNext (backward pass)

  • .Sum() calls MoveNext() on IEnum3
  • IEnum3 calls MoveNext() on IEnum2
  • IEnum2 calls MoveNext() on IEnum1
  • IEnum1 calls MoveNext() on IEnum0

3. Returning from MoveNext (forward-backward pass)

  • IEnum0 moves to element -1 and return true .
  • IEnum1 check if -1 satisfy condition (which is not true) so IEnum1 calls MoveNext() on IEnum0 .
  • IEnum0 moves to element 4 and return true .
  • IEnum1 check if 4 satisfy condition (which is true) and returns true
  • IEnum2 does nothing, just return output of IEnum1 which is true
  • IEnum2 does nothing, just return output of IEnum2 which is true

4. Calling Current (backward pass)

  • .Sum() calls Current on IEnum3 .
  • IEnum3 calls Current on IEnum2
  • IEnum2 calls Current on IEnum1
  • IEnum1 calls Current on IEnum0

5. Returning Current (forward pass)

  • IEnum0 returns 4
  • IEnum1 returns 4
  • IEnum2 returns sqrt(4)=2
  • IEnum3 returns exp(2)

6. Repeat steps 2.-5. until step 3. returns false

Please correct me if a chain query is processed in a different way.

You can use delegates to understand the order of execution. Example:

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;
}

Output:

-1 > 0: False

4 > 0: True

Math.Sqrt(4): 2

Math.Exp(2): 7.38905609893065

SumNumber(7.38905609893065)

9 > 0: True

Math.Sqrt(9): 3

Math.Exp(3): 20.0855369231877

SumNumber(20.0855369231877)

sumOfRoots = 27.4745930221183

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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