How does it work in C#? - Part 3 (C# LINQ in detail)

Language Integrated Query (LINQ) is a Microsoft .NET Framework component that works as a communicator between the objects and the data. This article partially taken from the "Expert C# 5.0" - book and it will explore the different extension methods used in the LINQ using C# and IL code to discuss..

LINQ basics

In .NET any data structure which is derived from the IEnumerable<T> interface
of the System.Collections.Generic namespace of the mscorlib.dll
(this assembly is located in C:\Windows\Microsoft.NET\Frameworkv4.0.30319 but depends on the installation of the VS) assembly is able to access
all the extension methods defined in the Enumerable class of the System.Linq namespace
of the System.Core.dll assembly in the .NET Framework (see more about LINQ).
This Enumerable class is a static non inheritable class defined in the System.Linq namespace of the System.Core.dll
assembly(C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll
but depends on the installation of VS). The definition of the Enumerbale class is as below:

Extension method - behind the scene - Now do bit of interesting work,
in this research I use ILDasm(C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\ildasm.exe but this is for my installed VS)
tool which comes as part of the VS installation. I use the same C# code as OP provided except change the class name Exte to ExtensionMethodClass.
I build the program and grab the exe of the program in this case it is ConsoleApplication24.exe (as I put the code in the console app which is called ConsoleApplication24.)
into the ILDasm program and ILDasm generate following IL code for the ExtensionMethodClass class in here we define the extension method.

Inside this class GetFirstThreeCh method has been compiled as static public method which has string type parameter.
Note that in here there is no this which we define in the C# code in the GetFirstThreeCh method.

So it is clear more this IL code that extension method has been define as same as static method.

Let’s see the usage of this GetFirstThreeCh extension method from the Main method which will show us the calling convention of the extension method in underneath.
I extracted the following IL code from the program class of the ConsoleApplication24.exe program using the ILdasm:

So any data structure derived from IEnumerable<TSource> interface is be able to access these two extension methods over that data structure such as List<T> class. List<T> class implemented the IEnumerable<T> interface as the signature of the List<T> class shows as below,

This code will create a list of string objects and store into a List<string> object, numbers. The above program will find out those items from the numbers whose total number of characters is equal to 3 and store the result into a new list, numbersLengthThree. Finally, display the number on the console. This program will produce the following output,

One
Two
Six

Let’s do bit of research to find out how does it work. The most important code from the above example is numbers.Where(x => x.Length == 3).Select(x => x).ToList(). Following diagram will explain the entire process of this execution.

Fig: How does Where and Select extension methods work.

From the above diagram we can see that the CLR passed the numbers list as input to the Where method along with the instance of the MulticastDelegate which holds the information about the <Main>b_1 method (created from anonymous method (x=>x.Length == 3) ). From the Where method it will return instance of the WhereListIterator<string> iterator which will then be used to pass as input parameter to the Select clause along with another instance of the MulticastDelegate class which will hold the information about the method <Main>b_2 (created from anonymous method (x=>x)). The Select method will instantiate the relevant Iterator based on the input. In this circumstance, it will be WhereSelectListIterator<string,string> iterator. This will be passed as input parameter to the ToList() method which will finally process the original list by iterating through to get the new list based on the filtering criteria. In depth of the execution will be as below,

Step 1: In the compile time, compiler will create a method <Main>b_1 using anonymous method provided for the Where methods i.e. for x => x.Length == 3.

Note: I decompiled the executable file produced by the above program using the ILDasm.exe (C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\ILDasm.exe depending on the VS installation) program and find out the generated method <Main>b_1 for x => x.Length == 3 code is as below,

The CLR will create an instance of the MulticastDelegate class using the method <Main>b_1 and store this method information into the MulticastDelegate instance and continue the operation.

Step 2: The CLR will continue the execution and goes to the Where<TSource>(this IEnumerable<TSource> source, Func predicate) method of the Enumerable class with the original list numbers and instance of MulticastDelegate (created in Step 1) as input to the Where method. Based on the source type of the numbers object, Where method will return the appropriate iterator instance as output. For example, based on the above example code it will return WhereListIterator<TSource> iterator which will contain the original list as source and <Main> b_1 as predicate inside it.

Note: Complete list of iterator’s class can be found in the System.Core.dll assembly as below,

Fig: Iterator classes used in the Enumerable clss of the System.Core.dll assembly.

The CLR will use WhereListIterator<TSource> to pass as parameter to the Select clause as input.

Step 3: In the compile time the compiler also created another method using anonymous method code (x=>x) which is <Main>b_2,

NOTE: the contents of the <Main>b_2 method extracted via the ILDasm.exe program from the executable of the above example program,

The CLR will use this as input parameter to the MulticastDelegateclass and create another instance of the MulticastDelegate type. It will then use the iterator instantiated from the Step 2 and delegate instance in this step as input for the Select clause and move the execution to the Select method.

Step 4: In the Select method of the Enumerable class CLR will instantiate the relevant iterator based on the input of the Enumerable object and the selector delegate. For the above example, it will return an instance of the WhereSelectListIteratoriterator. This iterator will contain the original list, the predicate delegate which hold the anonymous method <Main>b_1 and the selector delegate which will contain the anonymous method

b_2 inside it.

Step 5: The CLR pass this WhereSelectListIterator<string,string> iterator instance to the ToList() method as the input parameter. In the ToList() method CLR will create an instance of List<TSource> type by passing the WhereSelectListIterator<string,string> iterator as input to it.

Step 6: In the constructor of the List<TSource> class CLR will copy the list provided as input into a new list and iterate through the enumerator of the iterator (WhereSelectListIterator<string,string> ) over this new list. This will make sure original list does not alter and add the result into a dynamic array _items inside the List object. This list object will be returned as a result for the original list based on the filtering criteria. The approximate code for that is as below,

All

This extension method determines whether all elements of a sequence satisfy a condition, if every element of the source sequence passes the condition in the specified predicate, or if the sequence is empty return true; otherwise, false. Read more

This extension method used to determine whether a sequence of items meet a condition i.e. Each of the items in the sequence will be evaluated against the predicate. In the following program, I created an instance of the List<string> numbers which contains One, Two, Three and so on as items. Following program will find out whether the items of this sequence have at least three characters.

Because the extension method All will match the condition specified in the predicate whether it is valid for the item from the sequence or not. So it will be working as below,

Fig: All extension method working details.

From the above diagram we can see that the CLR will pass the numbers list as input to the extension method All along with the instance of the MulticastDelegate class created using the anonymous method (x=>x.Length >= 3) code. In the All method CLR will process the list to find out whether each of the items from the list meets the condition via the provided predicate.

The CLR will execute the extension method All as below,

Step 1: The compiler will construct a method <Main>b_1 using the anonymous method (x => x.Length >= 3) . The CLR will pass this <Main>b_1 method into the MulticastDelegate class to instantiate an instance of it. The CLR will pass the original list and the instance of the MulticastDelegate class created in this step as input to the extension method All of the Enumerable class.

Step 2: The All extension method will loop through the list and try to find out whether any element in the sequence does not meet the condition and return false otherwise a true value as a result of the operation. The approximate code for this logic is as be as below,

The sequence contains item.
The sequence contains at least a item which has three or more characters

When the CLR find out the first version of the Any extension method it will execute following steps to perform the operation,

Step 1: The CLR will send the original sequence or the list in this case numbers to the Any<TSource>(this IEnumerable<TSource> source) extension method as input.

Step 2: This method will loop through the list numbers via the Enumerator object return from the list numbers and check whether the enumerator return a true value while calling the MoveNext() method of it and returns true otherwise false i.e. the sequence does not have any element in it.

For the second version of the Any extension method CLR will do the following steps to execute,

Step 1: The compiler will construct a method <Main>b_1 using the anonymous method (x => x.Length >= 3) . The CLR will pass this <Main>b_1 method to the MulticastDelegate class to instantiate an instance of it and pass this MulticastDelegate instance as predicate along with the original list to the Any extension method.

Step 2: Inside the Any extension method CLR will loop through the list to execute the predicate using each item as input to the predicate. If the predicate return true of first iteration it will return true otherwise it will continue until find a match or not. The approximate code for the,

From the above diagram we can see that the CLR will pass the list numbers as input to the Average method. This method will process the original list by iterating through it and calculate the average of items stored into the numbers list and return the average of the items as result.

The second version of the Average extension method will do the following steps,

Step 1: The CLR will pass the original list and the instance of the MulticastDelegate type created using the <Main>b_1 method (which is generated in the compile time by the compiler using anonymous method (x=>x*2) ) as input to the Average extension method.

Step 2: The CLR will call the Select method (public static IEnumerable<TResult> Select(this IEnumerable<TSource> source, Func selector) ), it will instantiate WhereSelectListIterator iterator from this method and send back to the Select method.

Step 3: The CLR will then call Average method which it will accept the
iterator instance for example, WhereSelectListIterator created in Step 1 as input. This
iterator will contain the original list and the instance of the MulticastDelegate as the Selector.

Step 4: In the Average method ForEach statement will iterate through the list

foreach (int num3 in source)
{
num += num3;
num2 += 1L;
}

and perform the average calculation. Following image shows,

Fig: Average extension method working details.

From the above diagram we can see that the CLR will pass the list numbers as input to the Average extension method (Average(this IEnumerable source, Func selector) ) along with the instance of MulticaseDelegate class instantiated from anonymous method (x=>x*2) code. The CLR will pass this to the Select method from where the appropiate iterator will be instantitated and return to the Average method. In this case it will be WhereSelectListIterator iterator will be passed to the Average method to process the original list. The WhereSelectListIterator iterator will hold the original list and the selector inside. From the average method CLR will iterate through the list and calculate the average based on the on the filtering criteria provided in the Selector.

Concat

This extension method concatenates two sequences. This method is implemented by using deferred execution (please read here for more about the deferred execution). The immediate return value is an instance one of the relevant iterator type that stores all the information that is required to perform the action. The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach statement in C#. Read more.

The Concat<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) method differs from the Union method because
the Concat<TSource>(IEnumerable<TSource>, IEnumerable<TSource>) method returns all the original elements in the input sequences.
The Union method returns only unique elements from the sequences. The method signature for this extension method is as below,

From the above diagram we can see that the CLR passed the listOne and
listTwo as input to the Concat method and from the
Concat method it will return ConcatIterator instance as output to the caller of this extension method. Though this will be executed using deferred execution pattern, the ToList() method will start processing using the logic implemented in the
ConcatIterator class of listOne and listTwo to produce the final list.

When the CLR finds the Concat extension method it will execute following steps to perform the operation,

Step 1: The CLR will pass the original lists in this case listOne and listTwo to the Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) method as input parameter.

Step 2: From the Concat method CLR will return an instance of the ConcatIterator<int>
iterator which will hold the listOne and listTwo and return to the caller of the Concat method. The approximate code for the Concat method is as below,

Step 3: Due to the deferred execution this iterator will be executed by the
ToList() method which will loop through the lists such as listOne and
listTwo via the Enumerator object returned from the ConcatIterator instance and insert each of the item from listOne and listTwo to a new list and return as result.

So when the compiler finds the first version of the Contains method as in the above program, it will do the following steps to perform the operation,

The CLR will search a particular item into the list in the Contains method. This search will have two direction such as if the input is a null value
then it will loop through the list to match item with the null and return true if one of the item from the list is null otherwise false.
Other than null value CLR will compare the value (provided to match as input) with each of the item from the list, depending on match it will return a boolean answer.

Second version returns a number that represents how many elements in the specified sequence satisfy a condition.

The Count method will find out how many items in the list. For example in the following program I created a list of string objects. I use
Count() method to find out how many items in the list and also how many items which is more than
three characters.

Step 1: When the CLR finds the first version of the Count method it will try to find out the Enumerator object of given list and iterate through items (using the iterator of the list) unless the
MoveNext() method of the enumerator returns false.

Fig: Count extension method working details.

This method will return the number of iteration as the output of this program as the number of iteration will be the number of items in the list. The approximate code for the
Count is as below,

Step 2: The second version of the Count() method will accept the original list and a predicate to filter the count based on the condition. The predicate will be created in the compile time based on the anonymous method. The CLR will loop through the items of the list and execute the predicate over each of the item while looping through. If the predicate meet the condition over the item on iteration it will increase the item count. Finally it will return the item count as the total number of item which meets the condition. The approximate code for the Count method is as below,

From the above diagram we can see that the CLR passed the numbers list as input to the Count method along with the instance of the MulticastDelegate class created using <Main>b_1 which will created using the anonymous method (item=>item.Length > 3) code. In the count method CLR will iterate through each of the item and execute the delegate object against the item, depending on the return value of the delegate the number of count will increase and return the result as the total count of the list depends on the condition provided by (item=>item.Length > 3) .

The first version returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty.

The second version returns the elements of the specified sequence or the specified value in a singleton collection if the sequence is empty.

This method can be used on a list which does not have items in it and if we call the extension method over this list it will return default value of the item. Let’s see the following program which uses
DefaultIfEmpty method:

In the above program I declared three lists of person objects, numbers and names of type Person, int and string accordingly. These three lists do not have any item and Count Property of this list will return 0. When I call the
DefaultIfEmpty extension method over any of this list then the CLR will do the following steps to process it,

The CLR will copy the list to this DefaultIfEmpty method, from this method CLR will return the instance of the DefaultIfEmptyIterator<TSource> iterator which will hold the
defaultvalue and source value. The defaultvalue property will contain the default value of the type of list and source will be the original list.

The CLR will pass the DefaultIfEmptyItereator to the ToList() method which will call the the List class passing the object of the
DefaultIfEmptyItereator as input. In this class CLR will iterate through original list and process the result.

The first version returns distinct elements from a sequence by using the default equality comparer to compare values.

The second version returns distinct elements from a sequence by using a specified IEqualityComparer<T> to compare values.

The Distinct extension method will return the identical items from the list i.e. if we have a list which contains duplicate items using this method it will filtered the duplicated items and return a new list which will only contains the each of the item only once in the list. Let’s see the following program in where I use Distinct method on a list which contains a set of {1,1,1,2,2,2,3,3,3}.

When the above program will run it will produce {1, 2, 3} as output. Following diagram shows that how does distinct method works,

Fig: Distinct extension method working details.

To execute the Distinct method CLR will do the followings,

Step 1: The CLR will copy the original list to the Distinct method as input which will call the Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) method internally it will return an instance of the DistinctIterator<TSource>( IEnumerable<TSource> source, IEqualityComparer<TSource> comparer) class but this iterator will not execute due to the deferred execution (to execute the
DistinctIterator iterator we need to call the ToList() method over the list or need to do the ForEach).

Step 2: From the ToList() method CLR will call the List class by passing the
DistinctIterator created in Step 1 as input to it. The List class iterate through the instance of the
DistinctIterator. The iteration logic implemented in the DistinctIterator will create a new instance of the Set<TSource> and iterates through the original list and adds the iterated item in the Set<TSource> instance it created earlier. Internally the Set<TSource> class will use Add and Find method to add the item from the given sequence into the internal slots array only when there is no duplicate item in the array slot. This will continue until CLR reaches the end of the list and will get a list with distinct items.

This program is creating a numbers list which is storing One, Two and Three. From this numbers list I am trying to access the element which is stored in the position (array position) 1 and stored into the
elementAt variable to display on the console. This program will produce the following output,

Two

To execute the ElementAt method the CLR will do the following things,

Step 1: The CLR will call the get_Item method from the
System.Collections.Generic.List`1<T> class while executing
the ElementAt<TSource>(this IEnumerable<TSource> source, int index) extension method. The following code has been extracted
from the ElementAt method of the System.Linq.Enumerable class of the
mscorlib.dll assembly using
the ILDasm.exe program:

From the above code we can see that the CLR will call the get_Item(int32) method of the
System.Collections.Generic.List`1<T> class with the index provided from the caller of the
ElementAt method as input parameter in the label IL_001a.

Step 2: get_Item(int32) method of the System.Collections.Generic.List`1<T> class will load the _items array of this class (label IL_000f in the following IL code) and it will then load the argument (label IL_0014 in the following IL code) to get the index which will later use to access item from the _items array based on the index. If we see the IL code of the get_Item(int32) method from the System.Collections.Generic.List`1<T> class from the
mscorlib.dll using ILDasm:

From the above code ldfld IL instruction used in the IL_000f will load the _items field of the List<T> class and on IL_0014 label it will load the argument 1 which is the index will use to access the item from the _items array using the IL instruction
ldelem used in the IL_0015.

In the above code I created an empty list of int type using the
Empty() method. This program will produce the following output,

0

When the CLR will execute the Empty extension method it will do the following things to execute the operation.

Step 1: The CLR will call the get_Instance() method of the EmptyEnumerable`1<!!TResult> internal class from
the System.Linq namespace of the System.Core.dll assembly while executing the Empty<TResult>() method. This class has an array
field of given type (!!TResult) and a property Instance which will return the array field. The following IL code of the
Empty method has been
decompiled using the ILDasm.exe program from the System.Core.dll assembly.

Step 2: The Instance property from the System.Linq.EmptyEnumerable`1<!!TResult> will call the get_Instance() method. The get_Instance() method will create an array with 0 items. The CLR will first push 0 onto the stack as int32 type using ldc.i4.0 IL instruction used in the label IL_0007 in the following code. Using the
newarr IL instruction CLR will create a new array with the 0 item and will push on the stack. In the
label IL_000d, CLR will use stsfld to replace the value of the field value i.e. instance field’s value using the value from the stack.

The first version produces the set difference of two sequences by using the default equality comparer to compare values.

the second version produces the set difference of two sequences by using the specified
IEqualityComparer<T> to compare values.

The Except method can be used to remove a list of items from another. For example, if we have a list A with items {1,2,3,4,5,6,7} and B with {1,2,3} so the A except B will produce {4,5,6,7}. Following program used
Except to show its usage,

When the above program will run it will produce the {4,5,6,7}. Following
diagram shows that how the Except extension method works:

Fig: Except extension method working details.

The CLR will execute the Except method as following,

Step 1: The CLR will copy the original list to the Except method as input which will call the Except<TSource>(this IEnumerable<TSource> first,
this IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) method internally it will instantiate
the ExceptIterator<TSource>( this IEnumerable<TSource> first, this IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
iterator class. This iterator will not execute due to the deferred execution until the call the
ToList() method over the list or use ForEach statement.

Step 2: When the CLR will execute the ToList() method it will call the List class by passing
ExceptIterator instance created
in Step 1 as input. The List class will call the ExceptIterator method while it iterates through the list. The
ExceptIterator method
creates a new instance of the Set<TSource> type and iterates through the second list and adds the iterated item in the Set instance it created earlier.
Internally the method will use Add and Find method to add the item into the internal slots array only when there is no duplicate item in the slot. This will continue until compiler reaches the end of the second list. In the second loop CLR will iterate through the first list and try to add iterate item in the Set object it created in this step. If the item of second list does not exist in the set object then it will return that item and continue until it finishes the first list.

Union

The Union method will union (denoted as ?) of a collection of sets is the set of all distinct elements in the collection. Read more. For example, if we have two sets, A={1,2,3,4,5,6,7} and B={5,6,7,8,9} the Union of these sets will be A u B ={1,2,3,4,5,6,7,8,9}.

In .NET, the Union method will do the exactly as above diagram, it will join two list and create a new list.

Step 1: The Union method will instantiate a UnionIterator<TSource> which will hold the
firstList and the secondList and null for the IEqualityComparer as the above program does not provided any.

Step 2: Due to the deferred execution this UnionIterator<TSource> will be executed when the CLR will start executing the
ToList() method. Inside the UnionIterator<TSource> a new instance of the
Set<TSource> class will be instantiated which will be used to find out the distinct item from the both lists.

It produces the set intersection of two sequences by using the default equality comparer to compare values.

It produces the set intersection of two sequences by using the specified
IEqualityComparer<T> to compare values.

It produces the set intersection of two sequences. The intersect operation will produce those element which are common in the both list.
For example, if we have a list A with items {1, 2, 3, 4, 5} and B with {4, 5} then the intersection of these two list A n B will produce {4, 5}

Fig: Intersect operation.

Let’s see the following program which is creating two list named listA with values 1, 2, 3, 4, 5, and
listB with values 4, 5. I am doing an intersect operation between this two list using the Enumerable extension method
Intersect.

Step 1: The CLR will instantiate an instance of the IntersectIterator<TSource> and return to the caller. Due to the deferred execution this iterator will not execute until
ToList() method is being called.

Step 2: From the IntersectIterator<TSource>, the CLR will create an instance of the Set<TSource> object which used to hold all the items from the second list. The CLR will then iterate through the first list and try to remove each of the items of the first list from the Set<TSource> object. If it can remove then it will return the item of the
firstlist otherwise it will continue to iterate the first list until it can remove from the set. Following code shows the approximate code for the,
IntersectIterator method,

When the CLR will execute the first version of the Last extension method as below,

The original list will be passed to the Last <TSource>(this IEnumerable<TSource> source) method as input parameter.

This method will loop through the list via the Enumerator object returns from the list and check whether the enumerator return a true value while calling the MoveNext() method of it and returns true otherwise false, i.e., the sequence does not have any element in it.

For the second version of the Any extension method CLR will do following steps,

The compiler will construct a method <Main>b_1 using the anonymous method (item => item > 3) in the compile time. The CLR will pass this <Main>b_1 method to the MulticastDelegate class to construct an instance of it and pass this <Main>b_1 to the Last extension method.

The CLR will loop through the list and match with each element in the sequence based on condition provided in the predicate. This return on first match otherwise it will continue until find a match or not.

So when the CLR finds the first version of the Max method in the above program, it will do the following steps to perform the operation,

Step 1: The CLR will pass the original list as input to the Max method.

Fig: Max extension method working details.

Step 2: The Max method will loop through the list and perform the Max operation.

The second version of the Max extension method will do the following steps,

Step 1: The compiler will construct a method <Main>b_1 using the anonymous method (x => x * 2). The CLR will pass this <Main>b_1 method to the MulticastDelegate class to construct an instance of it and call the Select method of the list which will take original list and the instance of the MulticastDelegate class as input. It will then return the relevant iterator instance for example, for the above example it will be
WhereSelectListIterator<tsource,tresult> for the list as output.

Step 2: It will then call Max method which will accept only the Iterator. This Iterator will contain the original list and the instance of the MulticastDelegate. In the
Max method ForEach method will iterate through the list and perform the max calculation.

So when the CLR finds the first version of the Min extension method as in the above program, it will do the following steps to perform the operation,

The CLR will pass the original list as input to the Min extension method.

The Min method will loop through the list and perform the minimum calculation operation.

Fig: Min extension method working details.

The second version of the Min extension method will do the following steps,

Step 1: The CLR will call the Select method of the list which will take original list and the instance of the MulticastDelegate which will be instantiated using the <Main>b_1 method. The <Main>b_1 method will be created in the compile time based on the anonymous method (x=>x*2). It will return the appropriate iterator which will be the WhereSelectListIterator and pass as input to the internal Min method.

OfType

This extension method filters the elements of an IEnumerable based on a specified type using the deferred execution. The immediate return value is an object of the iterator class which stores all the information that is required to perform the action. Read more.

The above program will filter string values from the numbers list as I set string in
OfType method. So the program will produce following output,

One Two Three

Step 1: The CLR will pass the sequence for example numbers in the above example to the OfType method as input. Inside the
OfType method the CLR will instantiate the OfTypeIterator which will hold the original sequence inside it. The approximate code for the
OfType method is as below,

Step 2: The CLR will pass the instance of the OfTypeIterator<TResult> class to the
ToList() method which will pass this iterator to the List class and process the operation based on the iteration logic implemented in the
OfTypeIterator and produce codethe ranged sequence as output.

Range

It generates a sequence of integral numbers within a specified range, implemented by using deferred execution. The immediate return value is an instance of the relevant iterator instance that stores all the information that is required to perform the action. The method signature for this extension method is as below,

Step 1: The CLR will pass the start element and no of times or the length of the generated sequence to the Range method as input. Inside the Range method the CLR will return the
RangeIterator<int> which will hold all the related information such as start element and length of the sequence inside it. The approximate code for the Range method is as below,

RangeIterator<int> will not be executed (due to the deferred execution) until the CLR call the
ToList() method.

Fig: Range extension method

Step 2: The CLR will pass this RangeIterator<int> to the
ToList() method which will pass this iterator instance to the List class and process the operation based on the iteration logic implemented in the
RangeIterator<int> class and produce the ranged sequence as output. The approximate code for the
RangeIteraor<int> is as below,

Repeat

It generates a sequence that contains one repeated value is implemented by using deferred execution. The immediate return value is an object of the relevant iterator type that stores all the information that is required to perform the action. Read more

The Repeat method of the Enumerable class will generate a sequence of 1 at 5 times inside. It will produce the following output,

1 1 1 1 1

Step 1: The CLR will pass the element to repeat and no of times to repeat number to the Repeat method as input. Inside the Repeat method it will construct the
RepeatIterator<TResult> iterator which will hold all the related information to generate the sequence.

Fig: Repeat extension method.

Step 2: The CLR will pass this RepeatIterator<TResult> instance to the
ToList() method which will pass this iterator to the List class and process the operation based on the iteration logic implemented in the
RepeatIterator<TResult> and produce the repeated sequence as output.

Reverse

It inverts the order of the elements in a sequence is implemented by using deferred execution. The immediate return value is an object of the iterator type that stores all the information that is required to perform the action. Read more

Unlike OrderBy, this sorting method does not consider the actual values themselves in determining the order. Rather, it just returns the elements in the reverse order from which they are produced by the underlying source.

While the CLR will execute the above program, to process the Reverse method it will do the following steps,

Step 1: The CLR will pass the original sequence in this case the numbers object as input to the
Reverse method. Inside the Reverse method it will construct the
ReverseIterator<TSource> iterator which will hold all the information related to the original sequence.

Fig: Reverse extension method.

Step 2: The CLR will pass the ReverseIterator<TSource> instance to the
ToList() method which will pass this iterator to the List class and process the operation based on the iteration logic implemented in the
ReverseIterator<TSource> and produce the reversed sequence as output.

It returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.

It returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.

I wrote a small program to test the Single extension method. In this program I will use the Single method over the IList<string> object numbers which contains only one item One. Following example will return One as output because this is the exactly one item in the list and the Single method works only those List object which contains exactly 1 item inside,

If I modify the above code and add one more item in the numbers list and execute the program then we will get following error message,

Unhandled Exception: System.InvalidOperationException: Sequence contains more th
an one element
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
at Chapter_5.Program.Main(String[] args) in J:\Book\How Does it Work in C#\Bo
ok-Projects\HDIWIC\Chapter-5\Program.cs:line 16

Let’s now find out how does it works behind the scence,

Step 1: The CLR will make a new List<string> object using a copy of the original list and check whether the new list is null or not. If it is not null then it will check the number of items in the list. If the number of items in the list is 0 then the CLR will throw an exception otherwise it 1 then return the first and only item from the list. The approximate code will be as below,

If I change the numbers list by adding one more item whose length is more than
three character the program will fail by throwing following exception,

Unhandled Exception: System.InvalidOperationException: Sequence contains more th
an one matching element
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predic
ate)
at Chapter_5.Program.Main(String[] args) in J:\Book\How Does it Work in C#\Bo
ok-Projects\HDIWIC\Chapter-5\Program.cs:line 16

The CLR will execute the SingleOrDefault extension with following steps,

Step 1: The CLR will check whether the list is null or not. If not then make a copy of the original into a temporary list. It will check the number of items in the list if it is 0 then the CLR will return the default value of the provided type for example, string for the listStringWithoutItem.SingleOrDefault<string>() or inferred type from the list for example, listStringWithoutItem is a type of IList<string> so the inferred type will be string . Complete list default value Table is here

The approximate code for the SingleOrDefault extension method is as below,

Skip

It bypasses a specified number of elements in a sequence and then returns the remaining elements is implemented by using deferred execution. The immediate return value is an object of the relevant type that stores all the information that is required to perform the action. Read more

Skip method will iterate through the list and skip the specified number of items from the beginning of the list. The specified number will accept as parameter of the method.

The following program will create list of string type which will hold One, Two, Three, Four and Five as items of this list, On the list I applied the skip operation by providing 2 as the number of items to skip,

So the CLR will find the above code specially numbers.Skip(1) it will,

Step 1: The CLR will go to the Skip method of Enumerable class from the
System.Linq namespace. This method will return the instance of the
SkipIterator<TSource> which will hold the original list and the count which will define how many item to skip.

Step 2: As because of the deferred execution pattern, this
SkipIterator<TSource> will execute while for iterate it via the
ToList() method. So inside the SkipIterator method it will run a loop until the number of item to skip becomes 0. During this iteration it will move the current position of the inner
Enumerator object. While the number of item becomes 0 then it will loop through the list again to return the remaining item from the list.

The output shows the result list excluded those items whose Length is equal to 3. So while the CLR find the
SkipWhile method it will do the followings,

Step 1: The compiler will construct a method <Main>b_1 using the
anonymous method (number => number.Length == 3) in the compile time. The CLR will pass this <Main>b_1 method to the MulticastDelegate class to
instantiate an instance of it. So the CLR will pass the original list and predicate in this <Main>b_1 as input to the
SkipWhile method and it will return SkipWhileIterator which will hold the original list and <Main>b_1 as predicate.

Step 2: Inside SkipWhileIterator, CLR will loop through the original list one by one and execute the predicate over the item. If the predicate return false then it will return that item as a result item of the
SkipWhile method or otherwise if it return true then it will keep continue through the list until it finishes.

The CLR will create an instance of MulticastDelegate instance using the <Main>b_1 method.

Step 2: The CLR will pass the original list and MulticastDelegate instance created in the Step 1 as input to the Sum method which will call the Select method with original list and the MulticastDelegate object as input. The CLR will instantiate the relevant iterator and return back to the Sum method. The CLR will then call the overloaded
Sum() method.

Fig: Sum extension method working details.

Step 3: The CLR will iterate through the item from the original list based on the iterator and execute the given selector ie the delegate instance created in the Step 1 and sum all the modified item to complete the summation operation,

ThenBy

ThenBy extension method performs a subsequent ordering of the elements in a sequence in ascending order. This extension method is implemented by using deferred execution. The immediate return value is an object of the relevant type that stores all the information that is required to perform the action. Read more.

Step 1: The CLR pass the original list as input to the ToArray<TSource>(this IEnumerable<TSource> source) method as input, inside the
ToArray method it will create an instance of the Buffer<TSource> type by passing the original list object as input.

Step 2: The CLR will copy the each of the item from the original list to an internal array named items. The approximate code for the
ToArray() method will be as below,

ToDictionary

It creates a Dictionary<tkey,> from an IEnumerable<T>. If we want to create a dictionary object based on the data in a list
this method will do everything by self but we need to specify a field from the list data as a key.

I created a list of Person object and stored into a List object persons. Then I turned this persons list into a Dictionary using ToDictionary extension method. As we can see ToDictionary is taking an anonymous method as input. This anonymous method is actually a key selector which will select the key of the object from the list and set as key into the dictionary object. So from Person object, Id will be selected as key for the result dictionary and value will be person object itself, interesting enough the Id property will be used as Key for the Dictionary and also it will be stored into the person as it was initialized.

When the CLR do the following to execute the ToDictionary method,

Step 1: If we open the System.Linq.Enumerable namespace from the C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
assembly using ILDasm.exe program then we can see that the ToDictionary method interanlly
call interanl ToDictionary method which has the following signature,

Before the CLR call the above internal ToDictionary method from the ToDictionary extension method, it will create an element selector function. In this case though I
haven't provided any element selector the CLR will use the default element selector which is
IdentityFunction<TSource>.Instance.

Note:IdentityFunction<TSource>.Instance is an internal class which will be used as an element selector for the ToDictionary method. Following diagram shows this class from the System.Core.dll assembly,

Which will instantiate an instance of the Dictionary<TKey, TElement> class. It will then iterate through the original list, each of the iterate value will pass to the
KeySelector and ElementSelector function to extract the Key and Value from the iterate value.

As I provided (person => person.Id) as the KeySelector, the compiler will generate an anonymous method <Main>b_5 and pass to the
KeySelector which will return the Id from the person object and compiler will provide the
ElementSelector ( x=>x as in the IdentityFunction<telement> in where x=>x will converted as b__0) which will return the value itself, i.e., the person object with Name, Address and Id value inside.

Step 1: The ToList() extension method will accept an
IEnumerable object as input. It will pass this IEnumerable object as input to the
List<TSource> type. The approximate code of that will be as below,

Step 2: The List type will accept an IEnumerable<TSource> collection as input of the constructor. Inside the constructor the CLR will initialize the _items array with the type as TSource and define the initial size of the array with 4. It will then iterate through the enumerator of the input list object. The approximate code for the List constructor is be as below,

Step 3: In the iteration phase each of the item the CLR will retrieve pass to the
Add( TSource item) method to add into the _items array initialized (in the Step 2). The approximate code for the Add method is as below,

In the Add method the most import code is the line this.EnsureCapacity(this._size + 1). The size of this _items array is dynamic and it will be ensured by the
EnsureCapacity method.

Step 4: So after finishing the iteration the CLR will return the list object as the output of the
ToList() method which will contain elements returned from the given
IEnumerable<TSource> object inside the _items array.

Zip

It applies a specified function to the corresponding elements of two sequences, producing a sequence of the results. The method steps through the two input sequences, applying function
resultSelector to corresponding elements of the two sequences. The method returns a sequence of the values that are returned by
resultSelector. If the input sequences do not have the same number of elements, the method combines elements until it reaches the end of one of the sequences. For example, if one sequence has three elements and the other one has four, the result sequence has only three elements. The Zip extension method will combine two list items by item based on the provided combination logic. Based on the following method signature we can see it’s an extension of
IEnumerable<TFirst> type and accept IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> resultSelector items as input.

So the items of first and second list will be combined item by item together to produce a new list based on the combined logic provided into the
resultSelector Func. So we can the Zip method will combine each of the item in the list as below,

Fig: An example of Zip extension method.

Based on the above diagram I wrote a small program which will combine the
firstList which contains {1, 2, 3, 4} item with the secondList which contains {“One”,”Two”,”Three”,”Four”} with the combined logic, item from the first List + “:\t” + item from the
secondList.

Step 1: The compiler will construct a method <Main>b_2 using the anonymous method (x, y) => x + ":\t" + y. The CLR will pass this <Main>b_2 method to the MulticastDelegate class to instantiate an instance of it.

Note: If we decompile the executable produced by the program and drop into the ILDasm.exe program we can see that the compiler generated following method block for the (x, y) => x + ":\t" + y code,

Step 2: The CLR will pass the instance of the MulticastDelegate created in the step1 to the Zip method which will return the ZipIterator instance after doing few basic null checks. The ZipIterator instance will hold the first and second list and
resultSelector (instance of the MulticastDelegate created in step1) inside it.

Fig: The Zip method working details

Step 3: As this Zip extension method will execute using
deferred execution pattern, whenever the CLR execute the ToList() method it will iterate through the
ZipIterator enumerator. Inside the ZipIteraor enumerator CLR will iterate through each of the List and get the Current item from the each list and it will pass that Current item as input to the
resultSelector Func as the input. The resultSelector will then combine each of the provided items into one single item (for example, 1 from the
firstList and One from the secondList will be combined as 1: One) and return. This will continue until the both list has finished. In this iteration process if one of the list has less item than the other then it will only return same amount of item from the both list. For example, if list A has {A1,B1,C1,D1} items and B has{A2,B2,C2} then the result will be based on combination logic (+) processed result {A1A2, B1B2,C1C2}. The D1 from the A list will be deducted.

Well, if you're serious about writing you could try Apress[^] or Manning[^] for example.
I have never written a book, so I wouldn't know beyond that, but you could try to contact them.
A book very similiar to your own already exists[^] though. And it has 840 pages... It's pretty good actually.
Good luck!

delegate versus Linq.Expression based queries: allow for linq-to-object/xml as well as for linq-to-SQL

extension methods: for IEnumerable<T> and IQueryable<T>

You basically focus here on the tabular listing of the Enumerable extension methods only, but not on the underlying concepts. Your information is valuable but not sufficient IMHO, if you claim: C# Linq in detail.