3
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 (char c in query) Console.Write (c);

Exception occurs IndexOutOfRangeException. Why this exception occurs every thing looks fine.

Thanks in advance.

Solution

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

This works fine, what is the difference between these codes. kindly, share the details.

leppie
  • 115,091
  • 17
  • 196
  • 297
bilal
  • 648
  • 8
  • 26
  • I don't want the solution of this problem, i need the reason why it happens. – bilal Feb 27 '15 at 05:54
  • 2
    `i` is captured and being mutated, hence it is out of range after the for loop when you realise `query` – leppie Feb 27 '15 at 06:00
  • If only the compiler had a warning for this, this is a problem in the design on C#!!! Everyone hits the trap at some point. – Ian Ringrose Mar 17 '15 at 13:48
  • see also http://stackoverflow.com/questions/8898925/is-there-a-reason-for-cs-reuse-of-the-variable-in-a-foreach?rq=1 – Ian Ringrose Mar 17 '15 at 14:08

3 Answers3

6

The issue is because

  1. IEnumerables are lazy.
  2. the value of i is not captured.

The .Where queries are only actually evaluated when you start printing the output, at which point i == 5, leading to the index out of bounds exception.


To show more clearly what's going on, below are equivalent queries for each iteration of the loop (Note that query always refers to the original query):

i = 0;
query.Where(c => c != vowels[i]);

i = 1;
query.Where(c => c != vowels[i]).Where(c => c != vowels[i]);

i = 2;
query.Where(c => c != vowels[i]).Where(c => c != vowels[i]).Where(c => c != vowels[i]);

...

See how all queries refer to the same value for i? After the final iteration, i is incremented one more time, which causes the loop to stop. But now i == 5, which is not a valid index anymore!

Steven
  • 2,437
  • 5
  • 32
  • 36
1

As you are using IEnumerable, just add .ToList() or .ToArray() to your where clause, it will work

        IEnumerable<char> query = "Not what you might expect";
        string vowels = "aeiou";
        IEnumerable<char> result = "";
        for (int i = 0; i < vowels.Length; i++)
            query = query.Where(c => c != vowels[i]).ToList(); // or .ToArray()
        foreach (char c in query) Console.Write(c);

Hope it helps.

Mukesh Modhvadiya
  • 2,178
  • 2
  • 27
  • 32
-1

change the name of your variable query in this line

query = query.Where (c => c != vowels[i]);

chouaib
  • 2,763
  • 5
  • 20
  • 35