0
IEnumerable<char> query = "Not what you might expect";

query = query.Where(c=>c!='a');
query = query.Where(c=>c!='e');
query = query.Where(c=>c!='i');
query = query.Where(c=>c!='o');
query = query.Where(c=>c!='u');

foreach(char c in query) Console.Write(c);

Simple LINQ query building. My question is, why all this queries execute? Why not only the last one? How this is compiled, how program knows to return to query initialization? I hope you understand my question.

I Know this code works and it's intuitive, but what happens behind the scenes?

mxmissile
  • 11,464
  • 3
  • 53
  • 79
milandjukic88
  • 1,065
  • 3
  • 13
  • 30
  • 4
    You're assigning the result of each filter back to the query variable. Why wouldn't each one execute? – Jonathon Chase Jan 30 '20 at 21:57
  • 1
    Consider about it like about a `StringBuilder`, by calling `builder.Append(value).Append(another)` you will collect all data which need to be in the final string and by calling `.ToString()` you actually build a new string. – Fabio Jan 30 '20 at 21:58
  • 1
    I'm not sure I'm understanding your question. The last line does in fact execute. The "when" the `Where` statements are evaluated will be during GetEnumerator within your ForEach loop. – Mr. Young Jan 30 '20 at 21:58
  • query variable executes after foreach... so why program goes on query initialization? – milandjukic88 Jan 30 '20 at 22:03
  • 1
    Are you asking why each `Where` is executed for each iteration of the `foreach`? This would be due to LINQ being lazily evaluated. – Jonathon Chase Jan 30 '20 at 22:09
  • _so why program goes on query initialization_ - what you mean by "query initialization"? – Fabio Jan 30 '20 at 22:14
  • 1
    deferred execution – mxmissile Jan 30 '20 at 22:43
  • 1
    [`Where`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where?view=netframework-4.8) returns an [`IEnumerable`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1?view=netframework-4.8) (basically an enumerator); it does not "execute" anything. The execution is done when you iterate over the results, as you do with the `foreach`. So each call to `.Where` is simply returning a new `IEnumerable` with the added condition. – Rufus L Jan 30 '20 at 22:47
  • You might read this article for more information: [Basic Linq Query Operations](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/basic-linq-query-operations) – Rufus L Jan 30 '20 at 22:54

1 Answers1

5

If you were to write it this way, only the last query would execute:

IEnumerable<char> source = "Not what you might expect";

query = source.Where(c=>c!='a');
query = source.Where(c=>c!='e');
query = source.Where(c=>c!='i');
query = source.Where(c=>c!='o');
query = source.Where(c=>c!='u');

foreach(char c in query) Console.Write(c);

Only the last query executes because each line replaces the queries assigned above it.

Your example, on the other hand, is equivalent to this:

IEnumerable<char> source = "Not what you might expect";

query = source.Where(c=>c!='a').Where(c=>c!='e').Where(c=>c!='i').Where(c=>c!='o').Where(c=>c!='u');

foreach(char c in query) Console.Write(c);

In this example, each line appends to the queries assigned above it. So obviously all of the queries will execute.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • Yes,I figured out something. When function return IEnumerable program does nothing with it. Just remebers somewhere that it is called. Only when foreach starts (asks for enumerator) functions are executed. I'm I right? – milandjukic88 Jan 30 '20 at 22:52
  • 2
    Yes, that is right. It's called [deferred execution](https://stackoverflow.com/questions/47379362/how-does-deferred-linq-query-execution-actually-work). If you want immediate execution, simply call `ToList()`, and LINQ will execute immediately and put everything into a List data structure. – John Wu Jan 30 '20 at 22:55
  • Yes yes that's right.. defered execution. Now i cleared! Thanks – milandjukic88 Jan 30 '20 at 22:59