When an iteration variable is used to increment a loop

I'm reading Albahari O'Reilly's book, C # in a nutshell, and I'm in the Linq Query chapter. It describes the effect of delayed execution and variable capture when executing Linq queries. He gives the following common error example:

IEnumerable<char> query = "Not what you might expect";
string vowels = "aeiou";
for (int i = 0; i < vowels.Length; i++)
{
    query = query.Where(c => c != vowels[i]);
}
foreach (var c in query)
{
    Console.WriteLine(c);
}
Console.Read();

An IndexOutOfRangeExceptionis called after the request, but that makes no sense to me. I would expect that the lambda expression in the Where statement c => c!= vowles[i]would simply be evaluated in c => c != vowels[4]for the entire sequence due to the effect of delayed execution and variable capture. I went ahead and debugged to find out what the value iwas when the exception was raised, and found out that it had a value of 5? So, I went ahead and changed the condition condition in the for loop to i < vowels.Length-1;, and, indeed, no exception was thrown. Is the for loop iiterating on the most recent iteration to 5 or is linq doing somenthing else?

+2
source share
3 answers

For all goals and objectives (except for captured variables):

for (int i = 0; i < 10; i++)
    ....

:

int i = 0;
while (i < 10)
{
    ....
    i++;
}

, , , , false, 10.

, LINQPad:

void Main() { }

public static void Test1()
{
    for (int i = 0; i < 10; i++)
        Console.WriteLine(i);
}

public static void Test2()
{
    int i = 0;
    while (i < 10)
    {
        Console.WriteLine(i);
        i++;
    }
}

, :

Test1:                                            Test2:
IL_0000:  ldc.i4.0                                IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     // i                        IL_0001:  stloc.0     // i
IL_0002:  br.s        IL_000E                     IL_0002:  br.s        IL_000E
IL_0004:  ldloc.0     // i                        IL_0004:  ldloc.0     // i
IL_0005:  call        System.Console.WriteLine    IL_0005:  call        System.Console.WriteLine
IL_000A:  ldloc.0     // i                        IL_000A:  ldloc.0     // i
IL_000B:  ldc.i4.1                                IL_000B:  ldc.i4.1    
IL_000C:  add                                     IL_000C:  add         
IL_000D:  stloc.0     // i                        IL_000D:  stloc.0     // i
IL_000E:  ldloc.0     // i                        IL_000E:  ldloc.0     // i
IL_000F:  ldc.i4.s    0A                          IL_000F:  ldc.i4.s    0A 
IL_0011:  blt.s       IL_0004                     IL_0011:  blt.s       IL_0004
IL_0013:  ret                                     IL_0013:  ret         

, .

, for, , , , , , , , .

, , i , , , , , , .

.NET Fiddle, :

using System;

public class Program
{
    public static void Main()
    {
        Action a = null;
        for (int index = 0; index < 10; index++)
            a = () => Console.WriteLine(index);

        a();
    }
}

10.

+4

, , ​​ :

c => c != vowels[i]

Where , foreach. , (, Console.WriteLine(i);), i i. , , lambda i.

, i vowels.Length, , . .

for :

for (int i = 0; i < vowels.Length; i++)
{
    int index = i;
    query = query.Where(c => c != vowels[index]);
}

index , .

+1

, .

    private void button1_Click(object sender, EventArgs e)
    {
        IEnumerable<char> query = "Not what you might expect";
        string vowels = "aeiou";
        for (int i = 0; i < vowels.Length; i++)
        {
            Console.WriteLine("out: " + i);
            query = query.Where(c =>
            {
                Console.WriteLine("inner: " + i);
                return c != vowels[i];
            });
        }
        Console.WriteLine("before query");
        foreach (var c in query)
        {
            Console.WriteLine(c);
        }
        Console.Read();
    }
0

Source: https://habr.com/ru/post/1681050/


All Articles