LINQ is a lot of things, it is a combination of many small things.
This answer will be erratic, sorry. Itβs best to wait a bit and see if anyone else can generalize it better and do Google for the keywords that I use.
LINQ stands for " L anguage IN tegrated Q uery", and the most naive interpretation is this: they added an SQL-like syntax to the C # programming language.
So, instead of:
IEnumerable<int> values = otherValues.Where(i => i > 5);
they have the syntax:
IEnumerable<int> values = from i in otherValues where i > 5 select i;
The C # compiler actually translates the second piece of code into the first part of the code, so in fact you are just calling methods in collections.
However, here is another piece of the puzzle. These methods are not actually defined in collections at all. They are defined as extension methods, which means they are defined elsewhere, with some tricks that basically say βlet the programmer use these methods as if they were defined in the collection type to begin with, and just fix the code at compile time. "
So, the first part of the code is above:
IEnumerable<int> values = otherValues.Where(i => i > 5);
actually ends up compiling like:
IEnumerable<int> values = Enumerable.Where(otherValues, i => i > 5);
The Where method is defined here: Enumerable.Where .
The next piece of magic is that the C # compiler doesn't use Enumerable.Where what it does is that it just rewrites the code on the fly to look like the second piece of code in my answer here, and let the normal type output works. In other words, it's going to pretend that you actually wrote a second piece of code, and then see that "otherValues" is a List<T> , where T is int , and then discovers that Enumerable.Where is the one you call.
This means that you can actually create your own Where implementations for types other than collections, and the LINQ syntax will not be wiser.
This means ... things may be requested that are not actually stored in memory. For example, if "otherValues" above is what knows how to get data from the database, another Where method will be called, not the one specified in Enumerable.Where.
This allows other implementations to do their own thing, for example, writing SQL for you, executing it, and packaging the result so that it looks like the calling code, as if it were actually nested, memory for starters.
The next piece of magic is expression. The Where method parameter above, i => i > 5 is in most cases a lambda expression or an anonymous method, and you can actually declare it this way for a collection in memory:
Func<int, bool> w = delegate(int i) { return i > 5; }; IEnumerable<int> values = otherValues.Where(w);
However, support for expressions in C # means that you can also declare it as:
Expression<Func<int, bool>> w = i => i > 5;
Here, the compiler does not actually store it as a compiled part of the code, but rather a data structure in memory that knows that it takes one argument, compares it with 5 with more than the comparison, and returns the result.Note that you should use lambda- way to write, not as a delegate.
This knowledge allows those other Where implementations, if declared, to accept expressions, not only to hold the "where clause", but to look at it, highlight it, and rewrite it.
This means that the generation of this SQL can be done in the Where method, which knows how to handle SQL code.
Here's the LINQ to SQL declaration of the Where: Queryably.Where method.
So LINQ is a combination of many smaller pieces of technology added to the C # compiler: