Contents
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:
.class public abstract auto ansi sealed beforefieldinit System.Linq.Enumerable extends [mscorlib]System.Object
Note: The figure shows the Enumerable
class decompiled using the ILDasm.exe program,
Fig: Enumerable class in ILDasm.exe program.
The static Enumerable
class is a container of the different extension methods for the IEnumerable<T>
interface, for example,
public static bool Contains<TSource>(
this IEnumerable<TSource> source, TSource value)
{ }
public static int Count<TSource>(
this IEnumerable<TSource> source)
{ }
public static IEnumerable<TSource> Distinct<TSource>(
this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{ }
Please read more about extension methods here Or Chapter 04 of the Expert C# 5.0 with .NET Framework 4.5 book.
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.
.class public abstract auto ansi sealed beforefieldinit ExtensionMethodClass
extends [mscorlib]System.Object
{
.custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor()
.method public hidebysig static string GetFirstThreeCh(string str) cil managed
{
.custom instance void [System.Core]System.Runtime.CompilerServices.ExtensionAttribute::.ctor()
.maxstack 3
.locals init (
[0] string str2,
[1] bool flag)
}
}
If we look into the IL code above, we can see:
ExtensionMethodClass
class has been define as abstract and sealed.
- 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:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "my new String"
L_0006: stloc.0
L_0007: ldloc.0
L_0008: call string ConsoleApplication24.ExtensionMethodClass::GetFirstThreeCh(string)
L_000d: stloc.0
L_000e: ret
}
From the above IL code in L_0008 label we can see that GetFirstThreeCh
method has been call as same as CLR call static method.To test this I created
a small static class with a static method as below:
namespace ConsoleApplication24
{
class Program
{
static void Main(string[] args)
{
TestStaticMethod.TestMethod();
}
}
public class TestStaticMethod
{
public static void TestMethod()
{
}
}
}
After building this new program I decompiled using ILDasm program to generate the IL code which is as below:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
L_0000: nop
L_0001: call void ConsoleApplication24.TestStaticMethod::TestMethod()
L_0006: nop
L_0007: ret
}
So we can see that how does CLR handle the extension method in behind the scene.
And Iterators in here. A complete list of extension methods defined in the Enumerable
class is in here.
Let’s see how these extension methods work internally.
Go to the contents.
Extension Methods
Where and Select
Where and Select are two important extension methods of the IEnumerable<TSource>
interface defined in the Enumerable
class of the System.Core.dll assembly.
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
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,
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
For more information please see Where and Select. Let’s see an example in here where the Where and Select extension methods have been used.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>()
{
"One", "Two", "Three", "Four",
"Five", "Six", "Seven"
};
var numbersLengthThree =
numbers.Where(x => x.Length == 3).Select(x => x).ToList();
numbersLengthThree.ForEach(x => Console.WriteLine(x));
}
}
}
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,
.method private hidebysig static bool <Main>b__1(string x) cil managed
{
.maxstack 2
.locals init (
[0] bool CS$1$0000)
L_0000: ldarg.0
L_0001: callvirt instance int32 [mscorlib]System.String::get_Length()
L_0006: ldc.i4.3
L_0007: ceq
L_0009: stloc.0
L_000a: br.s L_000c
L_000c: ldloc.0
L_000d: ret
}
Or the equivalent C# code is as below,
private static bool <Main>b__1(string x)
{
return (x.Length == 3);
}
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,
.method private hidebysig static string <Main>b__2(string x) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
.maxstack 1
.locals init (
[0] string CS$1$0000)
L_0000: ldarg.0
L_0001: stloc.0
L_0002: br.s L_0004
L_0004: ldloc.0
L_0005: ret
}
Or the equivalent C# code,
private static string <Main>b__2(string x)
{
return x;
}
The CLR will use this as input parameter to the MulticastDelegate
class 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 WhereSelectListIterator
iterator. 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,
public List(IEnumerable<T> collection)
{
ICollection<T> is2 = collection as ICollection<T>;
if (is2 != null)
{
int count = is2.Count;
this._items = new T[count];
is2.CopyTo(this._items, 0);
this._size = count;
}
else
{
this._size = 0;
this._items = new T[4];
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
this.Add(enumerator.Current);
}
}
}
}
Go to the contents.
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
The signature of this extension method is as below,
public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
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.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>()
{
"One", "Two", "Three", "Four",
"Five", "Six", "Seven"
};
if (numbers.All<string>(x => x.Length >= 3))
Console.WriteLine("All numbers have at least three characters.");
}
}
}
The above program will produce following output,
All numbers 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,
public static bool All<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (!predicate(local))
{
return false;
}
}
return true;
}
The C# method has been derived from the following IL code which has been generated by ILDasm.exe program for the Enumerable
class of the System.Core.dll assembly,
.method public hidebysig static bool All<TSource>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!TSource> source,
class [mscorlib]System.Func`2<!!TSource, bool> predicate) cil managed
{
.custom instance void System.Runtime.CompilerServices.ExtensionAttribute::.ctor()
.maxstack 2
.locals init (
[0] !!TSource local,
[1] bool flag,
[2] class [mscorlib]System.Collections.Generic.IEnumerator`1<!!TSource> enumerator)
L_001c: ldarg.0
L_001d: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0>
[mscorlib]System.Collections.Generic.IEnumerable`1<!!TSource>::GetEnumerator()
L_0022: stloc.2
L_0023: br.s L_0039
L_0025: ldloc.2
L_0026: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<!!TSource>::get_Current()
L_002b: stloc.0
L_002c: ldarg.1
L_002d: ldloc.0
L_002e: callvirt instance !1 [mscorlib]System.Func`2<!!TSource, bool>::Invoke(!0)
L_0033: brtrue.s L_0039
L_0035: ldc.i4.0
L_0036: stloc.1
L_0037: leave.s L_004f
L_0039: ldloc.2
L_003a: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
L_003f: brtrue.s L_0025
L_0041: leave.s L_004d
L_0043: ldloc.2
L_0044: brfalse.s L_004c
L_0046: ldloc.2
L_0047: callvirt instance void [mscorlib]System.IDisposable::Dispose()
L_004c: endfinally
L_004d: ldc.i4.1
L_004e: ret
L_004f: ldloc.1
L_0050: ret
.try L_0023 to L_0043 finally handler L_0043 to L_004d
}
Go to the contents.
Any
This extension method determines whether any element of a sequence exists or satisfies a condition provided as predicate. Read more.
The method signature for this extension method is as be as below,
public static bool Any<TSource>(this IEnumerable<TSource> source)
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The above two extension methods will do the following
- First version of the
Any
extension method will find out whether the sequence of items contains any element in it or not.
- Second version of the
Any
extension method will find out is there any element in the sequence which match the criteria provided in the predicate.
I wrote a small program to explain the working details of those two versions of extension methods from the Enumerable
class.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>()
{
"One", "Two", "Three", "Four",
"Five", "Six", "Seven"
};
if (numbers.Any<string>())
Console.WriteLine("The sequence contains item.");
if (numbers.Any<string>(x => x.Length >= 3))
Console.WriteLine("The sequence contains at least a item which has three or more characters");
}
}
}
The above program will produce the following output,
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.
The approximate code for the Any
extension method is as below,
public static bool Any<TSource>(this IEnumerable<TSource> source)
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return true;
}
}
return false;
}
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,
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (predicate(local))
{
return true;
}
}
return false;
}
Go to the contents.
Average
The Average
extension method calculates the average of a sequence of numeric values. Read more.
The method signature of these extension methods are below,
public static double Average(this IEnumerable<int> source)
public static decimal Average<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector)
An example of the Average
extension method is as below,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,2,3,4,5,6,7,8,9,10
};
Console.WriteLine("Average of the numbers :{0}", numbers.Average());
Console.WriteLine("Average of the original numbers x2 :{0}",
numbers.Average((x => x * 2)));
}
}
}
The above program will produce the following output,
Average of the numbers :5.5
Average of the original numbers x2 :11
So when the CLR will find out the first version of the Average
method as in the above program, it will do the following steps to perform the operation,
Step 1: The CLR will pass the original list in this case numbers as input to the Average
method.
Step 2: The Average method will loop through the list and perform the average operation for the given list. The approximate code is as below,
public static double Average(this IEnumerable<int> source)
{
long num = 0L;
long num2 = 0L;
foreach (int num3 in source)
{
num += num3;
num2 += 1L;
}
return (((double) num) / ((double) num2));
}
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 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.
Go to the contents.
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,
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
The following program will show the usage of the Concat
method,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> listOne = new List<int>()
{
1,2,3,4,5
};
IList<int> listTwo = new List<int>()
{
6,7,8,9,10
};
var result = listOne.Concat(listTwo).ToList();
result.ForEach(x=> Console.WriteLine(x));
}
}
}
The above program will produce the following output,
1
2
3
4
5
6
7
8
9
10
The Concat
extension works as below:
Fig: Concat extension method working details.
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,
public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
{
return ConcatIterator<TSource>(first, second);
}
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.
Go to the contents.
Contains
The Contains
extension method determines whether a sequence contains a specified element. Read more
This method will work as below,
- It determines whether a sequence contains a specified element by using the default equality comparer.
- Determines whether a sequence contains a specified element by using a specified
IEqualityComparer<T>
.
The method signature for this extension method is as below,
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value, IEqualityComparer<TSource> comparer)
This method will search the list whether it has a particular value in it or not. To explain this method I wrote a small program:
using System;
using System.Collections;
using System.Collections.Generic;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> listOne = new List<int>()
{
1,2,3,4,5
};
var resultAsTrue = listOne.Contains(2);
var resultAsFalse = listOne.Contains(200);
Console.WriteLine("{0}\n{1}", resultAsTrue, resultAsFalse);
}
}
}
The above program will produce the following output,
True
False
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.
The approximate code of the Contains
method is as below,
public bool Contains(T item)
{
if (item == null)
{
for (int j = 0; j < this._size; j++)
{
if (this._items[j] == null)
{
return true;
}
}
return false;
}
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < this._size; i++)
{
if (comparer.Equals(this._items[i], item))
{
return true;
}
}
return false;
}
Go to the contents.
Count
This count extension method returns the number of elements in a sequence. Read more.
The method signature for this extension method is as below,
public static int Count<TSource>(this IEnumerable<TSource> source)
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The above two extension methods will do the followings,
- First version returns the number of elements in a sequence.
- 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.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> listOne = new List<string>()
{
"One","Two","Three"
};
var result = listOne.Count();
var fourOrMoreCharacters = listOne.Count(item => item.Length > 3);
Console.WriteLine("{0}\n{1}", result,fourOrMoreCharacters);
}
}
}
The above program will produce the following output,
3
1
In this example I use two different version of Count method,
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,
public static int Count<TSource>(this IEnumerable<TSource> source)
{
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{num++;}
}
return num;
}
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,
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (predicate(local))
{
num++;
}
}
return num;
}
Fig: Count extension method working details.
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)
.
Go to the contents.
DefaultIfEmpty
This extension method returns the elements of an IEnumerable<T>
, or a default valued singleton collection if the sequence is empty. Read more
The signature for this extension method is as below:
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source)
public static IEnumerable<TSource> DefaultIfEmpty<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
The above two extension methods will do the followings,
- 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:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<Person> persons = new List<Person>();
IList<int> numbers = new List<int>();
IList<string> names = new List<string>();
var defaultPersons = persons.DefaultIfEmpty();
var defaultNumbers = numbers.DefaultIfEmpty().ToList();
var defaultNames = names.DefaultIfEmpty();
}
}
class Person
{
public string Name
{
get;
set;
}
public string Address
{
get;
set;
}
public int Age
{
get;
set;
}
}
}
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.
Fig: DefaultIfEmpty extension method working details.
The approximate code for the DefaultIfEmptyIterator
is as below,
private static IEnumerable<TSource> DefaultIfEmptyIterator<TSource>(IEnumerable<TSource> source, TSource defaultValue)
{
using (IEnumerator<TSource> iteratorVariable0 = source.GetEnumerator())
{
if (iteratorVariable0.MoveNext())
do
{
yield return iteratorVariable0.Current;
}
while (iteratorVariable0.MoveNext());
else
yield return defaultValue;
}
}
Go to the contents.
Distinct
This extension method returns distinct elements from a sequence. Read more.
The method signature of this extension method is as below,
public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source)
public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
The above two extension methods will do the followings,
- 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}.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,1,1,2,2,2,3,3,3
};
var distinctedNumbers = numbers.Distinct().ToList();
distinctedNumbers.ForEach(x=>Console.WriteLine(x));
}
}
}
This program will produce following output,
1
2
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.
So the Distinct method will work as below over a list,
private static IEnumerable<TSource> DistinctIterator<TSource>(
IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
Set<TSource> iteratorVariable0 = new Set<TSource>(comparer);
foreach (TSource iteratorVariable1 in source)
{
if (iteratorVariable0.Add(iteratorVariable1))
{
yield return iteratorVariable1;
}
}
}
Go to the contents.
ElementAt
This extension method returns the element at a specified index in a sequence. Read more.
The method signature for this extension method is as below,
public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index)
public static TSource ElementAtOrDefault<TSource>(this IEnumerable<TSource> source, int index)
Following shows an example of ElementAt
extension method of the IEnumerable<TSource>
interface.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>()
{
"One","Two","Three"
};
var elementAt = numbers.ElementAt(1);
Console.WriteLine(elementAt);
}
}
}
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:
.method public hidebysig static !!TSource ElementAt<TSource>(
class [mscorlib]System.Collections.Generic.IEnumerable`1<!!TSource> source,
int32 index) cil managed
{
IL_0018: ldloc.0
IL_0019: ldarg.1
IL_001a: callvirt instance !0 class
[mscorlib]System.Collections.Generic.IList`1<!!TSource>::get_Item(int32)
IL_001f: ret
}
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:
.method public hidebysig newslot specialname virtual final
instance !T get_Item(int32 index) cil managed
{
IL_000e: ldarg.0
IL_000f: ldfld !0[] class System.Collections.Generic.List`1<!T>::_items
IL_0014: ldarg.1
IL_0015: ldelem !T
IL_001a: ret
}
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.
Go to the contents.
Empty
Empty extension method returns an empty IEnumerable<T>
that has the specified type argument. Read more.
The method signature for this extension is as below,
public static IEnumerable<TResult> Empty<TResult>()
Following example shows the usage of the Empty
method,
using System;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
var emptyList = Enumerable.Empty<int>();
Console.WriteLine(emptyList.Count());
}
}
}
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.
.method public hidebysig static class
[mscorlib]System.Collections.Generic.IEnumerable`1<!!TResult>
Empty<TResult>() cil managed
{
IL_0000: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!0>
class System.Linq.EmptyEnumerable`1<!!TResult>::get_Instance()
IL_0005: ret
}
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.
.method public hidebysig specialname static
class [mscorlib]System.Collections.Generic.IEnumerable`1<!TElement>
get_Instance() cil managed
{
.maxstack 8
IL_0000: ldsfld !0[] class System.Linq.EmptyEnumerable`1<!TElement>::'instance'
IL_0005: brtrue.s IL_0012
IL_0007: ldc.i4.0
IL_0008: newarr !TElement
IL_000d: stsfld !0[] class System.Linq.EmptyEnumerable`1<!TElement>::'instance'
IL_0012: ldsfld !0[] class System.Linq.EmptyEnumerable`1<!TElement>::'instance'
IL_0017: ret
}
Go to the contents.
Except
The Except
method can be used to remove a list of items from another. It produces the set difference of two sequences. Read more
The method signature for this extension method is as below,
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first,
IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
The above two extension methods will do the followings,
- 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,
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> firstNumbers = new List<int>()
{
1,2,3,4,5,6,7
};
IList<int> secondNumbers = new List<int>()
{
1,2,3
};
var result = firstNumbers.Except(secondNumbers).ToList();
result.ForEach(x => Console.WriteLine(x));
}
}
}
This program will produce the following output,
4
5
6
7
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.
The approximate code of the ExceptIterator
will be as below,
private static IEnumerable<TSource> ExceptIterator<TSource>(
IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
Set<TSource> iteratorVariable0 = new Set<TSource>(comparer);
foreach (TSource local in second)
{
iteratorVariable0.Add(local);
}
foreach (TSource iteratorVariable1 in first)
{
if (!iteratorVariable0.Add(iteratorVariable1))
{
continue;
}
yield return iteratorVariable1;
}
}
So the
Distinct
method will work as below over a list,
Go to the contents.
First
It returns the first element of a sequence. Read more.
The method signature is be as below,
public static TSource First<TSource>(this IEnumerable<TSource> source)
public static TSource First<TSource>(this IEnumerable<TSource> source,Func<TSource, bool> predicate)
The above two First extension methods will do the following,
- First version of this extension method will find out the first item from the sequence of items.
- Second version of this extension method will find out the first item of list which meets the predicate condition.
I wrote a small program to explain the working steps for those two versions of
the First
extension methods of Enumerable
class.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,2,3,4,5,6,7
};
var firstItem = numbers.First();
var firstItemBasedOnConditions = numbers.First(item => item > 3);
Console.WriteLine("{0}\n{1}",
firstItem,
firstItemBasedOnConditions
);
}
}
}
This program will produce the following output:
1
4
When the CLR will execute the first version of the First extension method with following steps to perform the operation,
- The CLR sends the original list to the
First <TSource>(this IEnumerable<TSource> source)
method as input parameter.
- This method will return first item from the original list or iterate through the original list and return the first item from the iteration as a result.
The approximate code for this will be as below,
public static TSource First<TSource>(this IEnumerable<TSource> source)
{
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
if (list.Count > 0)
{
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return enumerator.Current;
}
}
}
}
For the second version of the First extension method CLR will do following steps,
- The compiler will construct a method
<Main>b_1
using the anonymous (item => item > 3)
. The CLR will pass this <Main>b_1
method to the MulticastDelegate
class to construct an instance of it.
- First method will loop through the list and match with each element in the sequence based on the predicate. This return on first match otherwise it will continue until find a match or not.
The approximate code for the,
public static TSource First<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (predicate(local))
{
return local;
}
}
}
Go to the contents.
FirstOrDefault
It returns the first element of a sequence, or a default value if no element is found. Read more.
The method signature for the FirstOrDefault
extension is as below:
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The above two extension method will do the followings,
- It returns the first element of a sequence, or a default value if the sequence contains no elements.
- It returns the first element of the sequence that satisfies a condition or a default value if no such element is found.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> firstNumbers = new List<int>();
IList<int> secondNumbers = new List<int>()
{
1,2,3,4,5,6,7
};
var firstItemOfFirstList = firstNumbers.FirstOrDefault();
var firstItemIfFirstListBasedOnConditions =
firstNumbers.FirstOrDefault(item => item > 3);
var firstItemOfSecondList = secondNumbers.FirstOrDefault();
var firstItemOfSecondListBasedOnConditions =
secondNumbers.FirstOrDefault(item => item > 3);
Console.WriteLine("{0}\n{1}\n{2}\n{3}",
firstItemOfFirstList,
firstItemIfFirstListBasedOnConditions,
firstItemOfSecondList,
firstItemOfSecondListBasedOnConditions
);
}
}
}
This program will produce the following output,
0
0
1
4
Approximate code for the first version of the FirstOrDefault
extension method:
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
if (list.Count > 0)
{
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
return enumerator.Current;
}
}
}
return default(TSource);
}
Approximate for the second version of the FirstOrDefault
extension method:
public static TSource FirstOrDefault<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (predicate(local))
{
return local;
}
}
return default(TSource);
}
Go to the contents.
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.
public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first,
IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
The following program shows the usage of the Union
operation:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> firstList = new List<int>()
{
1,2,3,4
};
IList<int> secondList = new List<int>()
{
7,9,3,4,5,6,7
};
var result = firstList.Union(secondList);
result.ToList().ForEach(x => Console.WriteLine(x));
}
}
}
This program will produce the following output,
1
2
3
4
7
9
5
6
When the CLR will execute the Union method as below,
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.
The approximate code for the UnitonIterator
will be as below,
private static IEnumerable<TSource> UnionIterator<TSource>(
IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
Set<TSource> iteratorVariable0 = new Set<TSource>(comparer);
foreach (TSource iteratorVariable1 in first)
{
if (iteratorVariable0.Add(iteratorVariable1))
{
yield return iteratorVariable1;
}
}
foreach (TSource iteratorVariable2 in second)
{
if (!iteratorVariable0.Add(iteratorVariable2))
{
continue;
}
yield return iteratorVariable2;
}
}
Go to the contents.
Intersect
It produces the set intersection of two sequences. Read more.
The method signature for this extension method is as below:
public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second)
public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first,
Enumerable<TSource> second,IEqualityComparer<TSource> comparer)
The above extension methods will do the followings,
- 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
.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> listA = new List<int>() { 1, 2, 3, 4, 5 };
IList<int> listB = new List<int>() { 4, 5 };
var intersectResult = listA.Intersect(listB);
intersectResult.ToList().ForEach(x => Console.Write("{0}\t",x));
Console.WriteLine();
}
}
}
This program will produce the following output:
4 5
To execute the Intersect extension method the CLR will do,
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,
private static IEnumerable<TSource> IntersectIterator<TSource>(
IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
Set<TSource> iteratorVariable0 = new Set<TSource>(comparer);
foreach (TSource local in second)
{
iteratorVariable0.Add(local);
}
foreach (TSource iteratorVariable1 in first)
{
if (!iteratorVariable0.Remove(iteratorVariable1))
{
continue;
}
yield return iteratorVariable1;
}
}
Go to the contents.
Last
It returns the last element of a sequence. Read more
The method signature for this extension method is as below,
public static TSource Last<TSource>(this IEnumerable<TSource> source)
public static TSource Last<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The above two First extension methods will do the following
- First version of this extension method will find out the first item from the sequence of items.
- Second version of this extension method will find out the first item of list which meets the predicate condition.
I wrote a small program to explain the working steps for those two versions of
Last
extension methods of Enumerable class.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,2,3,4,5,6,7
};
var lastItem = numbers.Last();
var lastItemBasedOnConditions = numbers.Last(item => item > 3);
}
}
}
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.
The approximate code for this will be as below,
public static TSource Last<TSource>(this IEnumerable<TSource> source)
{
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
int count = list.Count;
if (count > 0)
{
return list[count - 1];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
TSource current;
do
{
current = enumerator.Current;
}
while (enumerator.MoveNext());
return current;
}
}
}
throw Error.NoElements();
}
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.
The approximate code for the,
public static TSource Last<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
TSource local = default(TSource);
bool flag = false;
foreach (TSource local2 in source)
{
if (predicate(local2))
{
local = local2;
flag = true;
}
}
return local;
}
Go to the contents.
LastOrDefault
It returns the last element of a sequence, or a default value if no element is found. Read more
The method signature for this extension method is as below,
public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source)
public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The above extension method will for the followings,
- It returns the last element of a sequence, or a default value if the sequence contains no elements.
- It returns the last element of a sequence that satisfies a condition or a default value if no such element is found.
I wrote an example of discuss the LastOrDefault
extension method,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> firstNumbers = new List<int>();
IList<int> secondNumbers = new List<int>()
{
1,2,3,4,5,6,7
};
var lastItemOfFirstList = firstNumbers.LastOrDefault();
var lastItemIfFirstListBasedOnConditions =
firstNumbers.LastOrDefault(item => item > 3);
var lastItemOfSecondList = secondNumbers.LastOrDefault();
var lastItemOfSecondListBasedOnConditions =
secondNumbers.LastOrDefault(item => item > 3);
Console.WriteLine("{0}\n{1}\n{2}\n{3}",
lastItemOfFirstList,
lastItemIfFirstListBasedOnConditions,
lastItemOfSecondList,
lastItemOfSecondListBasedOnConditions
);
}
}
}
This program will produce the following output:
0
0
7
7
The approximate code of the first version of the LastOfDefault
extension method is as below,
public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source)
{
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
int count = list.Count;
if (count > 0)
{
return list[count - 1];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
{
TSource current;
do
{
current = enumerator.Current;
}
while (enumerator.MoveNext());
return current;
}
}
}
return default(TSource);
}
The approximate code of the the second version of the LastOfDefault
extension method is as below,
public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
TSource local = default(TSource);
foreach (TSource local2 in source)
{
if (predicate(local2))
{
local = local2;
}
}
return local;
}
Go to the contents.
LongCount
It returns an Int64 that represents the number of elements in a sequence. Read more
The method signature for this extension method is as below,
public static long LongCount<TSource>(this IEnumerable<TSource> source)
public static long LongCount<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
The above extension method will do as below,
- Returns an
Int64
that represents the total number of elements in a sequence.
- Returns an
Int64
that represents how many elements in a sequence satisfy a condition.
Let’s do an example,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> firstList = new List<int>()
{
1,2,3,4
};
Console.WriteLine(firstList.LongCount());
}
}
}
The program will produce following output,
4
The approximate code of the the first version of the LongCount
extension method is as below,
public static long LongCount<TSource>(this IEnumerable<TSource> source)
{
long num = 0L;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
num += 1L;
}
}
return num;
}
The approximate code of the the second version of the LongCount
extension method is as below,
public static long LongCount<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
long num = 0L;
foreach (TSource local in source)
{
if (predicate(local))
{
num += 1L;
}
}
return num;
}
Go to the contents.
Max
In .NET, five overloaded Max
extension methods have been defined in the
Enumerable
class. Read more.
public static int Max(this IEnumerable<int> source)
public static decimal Max<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal> selector)
An example of the Max
extension method is as below:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,2,3,4,5,6,7,8,9,10
};
Console.WriteLine("Max of the numbers :{0}", numbers.Max());
Console.WriteLine("Max of the original numbers x2 :{0}", numbers.Max(x => x * 2));
}
}
}
The above program will produce following output,
Max of the numbers :10
Max of the original numbers x2 :20
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.
Following image shows:
Fig: Max extension method working details.
Go to the contents.
Min
This extension method will find out the minimum of the list. Read more. The signature of the extension methods Min are below,
public static int Min(this IEnumerable<int> source)
public static int Min<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
An example of the Min
Extension method is as below,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,2,3,4,5,6,7,8,9,10
};
Console.WriteLine("Min of the numbers :{0}", numbers.Min());
Console.WriteLine("Min of the original numbers x2 :{0}", numbers.Min(x => x * 2));
}
}
}
The program will produce the following output,
Min of the numbers :1
Min of the original numbers x2 :2
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.
Step 2: Inside the Min method CLR will perform the minimum calculation operation and return the result.
Following image shows,
Fig: Min extension method working details.
Go to the contents.
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 signature of this extension method is as below,
public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
Example of OfType<TResult>
:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<object> numbers = new List<object>()
{
"One",
"Two",
1,
2,
"Three",
new Person
{
Name="A Person"
}
};
var filteredNumbers = numbers.OfType<string>();
filteredNumbers.ToList().ForEach(x => Console.Write("{0}\t", x));
Console.WriteLine();
}
}
public class Person
{
public string Name { get; set; }
}
}
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,
public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
{
return OfTypeIterator<TResult>(source);
}
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.
The approximate code for the RangeIteraor is as below,
private static IEnumerable<TResult> OfTypeIterator<TResult>(IEnumerable source)
{
IEnumerator enumerator = source.GetEnumerator();
while (enumerator.MoveNext())
{
object current = enumerator.Current;
if (current is TResult)
{
yield return (TResult) current;
}
}
}
Go to the contents.
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,
public static IEnumerable<int> Range(int start, int count)
Read more.
This method will create a list of int
item based on the start number to till the number of times defined in the count.
using System;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
Enumerable.Range(1, 10).ToList().ForEach(x => Console.Write("{0}\t", x));
}
}
}
The program will produce the following output,
1 2 3 4 5 6 7 8 9 10
The CLR will do the followings,
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,
public static IEnumerable<int> Range(int start, int count)
{
long num = (start + count) - 1L;
if ((count < 0) || (num > 0x7fffffffL))
{
throw Error.ArgumentOutOfRange("count");
}
return RangeIterator(start, count);
}
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,
private static IEnumerable<int> RangeIterator(int start, int count)
{
int iteratorVariable0 = 0;
while (true)
{
if (iteratorVariable0 >= count)
{
yield break;
}
yield return (start + iteratorVariable0);
iteratorVariable0++;
}
}
Go to the contents.
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 method signature of this extension method is as below,
public static IEnumerable<TResult> Repeat<TResult>(TResult element, int count)
It will generate a sequence of a number defined by the TResult
type of a number of times measured by count.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
Enumerable.Repeat(1, 5).ToList().ForEach(x=>Console.Write("{0}\t",x));
}
}
}
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.
The approximate code for the Repeat method is as below,
private static IEnumerable<TResult> RepeatIterator<TResult>(TResult element, int count)
{
int iteratorVariable0 = 0;
while (true)
{
if (iteratorVariable0 >= count)
{
yield break;
}
yield return element;
iteratorVariable0++;
}
}
Go to the contents.
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.
public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source)
It will reverse the original list, following example shows the usage of the
Reverse
extension method,
using System;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>() { 1, 2, 3, 4, 5 };
var reverseNumbers = numbers.Reverse();
var result = reverseNumbers.ToList();
result.ForEach(x => Console.Write("{0}\t", x));
Console.WriteLine();
}
}
}
This program will produce the following output,
5 4 3 2 1
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.
Approximate code for the ReverseIterator<TSource>
:
private static IEnumerable<TSource> ReverseIterator<TSource>(
IEnumerable<TSource> source)
{
Buffer<TSource> iteratorVariable0 = new Buffer<TSource>(source);
int index = iteratorVariable0.count - 1;
while (true)
{
if (index < 0)
{
yield break;
}
yield return iteratorVariable0.items[index];
index--;
}
}
Go to the contents.
Single
This extension method returns a single, specific element of a sequence. Read more.
The method signature for the extension method is as below,
public static TSource Single<TSource>(this IEnumerable<TSource> source)
public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source)
public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source,Func<TSource, bool> predicate)
The above extension method will do the followings,
- 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,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>
{
"One"
};
var result = numbers.Single();
Console.WriteLine("{0}", result);
}
}
}
The above program will produce following output,
One
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,
public static TSource Single<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
switch (list.Count)
{
case 0:
throw Error.NoElements();
case 1:
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
throw Error.NoElements();
}
TSource current = enumerator.Current;
if (!enumerator.MoveNext())
{
return current;
}
}
}
throw Error.MoreThanOneElement();
}
Let’s try the Single
extension method with a predicate function. I wrote a small program as below,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>
{
"One","Four"
};
var result = numbers.Single(x => x.Length > 3);
Console.WriteLine("{0}", result);
}
}
}
This program will produce the following output,
Four
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
I wrote an example of the SingleOrDefault
extension method as below,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> listStringWithoutItem = new List<string>();
IList<string> listStringWithItem = new List<string>() { "One" };
IList<int> listInt = new List<int>();
IList<char> listChar = new List<char>();
IList<long> listLong = new List<long>();
IList<double> listDouble = new List<double>();
var resultStringWithoutItem = listStringWithoutItem.SingleOrDefault();
var resultStringWithItem = listStringWithItem.SingleOrDefault();
var resultInt = listInt.SingleOrDefault();
var resultChar = listChar.SingleOrDefault();
var resultLong = listLong.SingleOrDefault();
var resultDouble = listDouble.SingleOrDefault();
Console.WriteLine("string : {0}", resultStringWithoutItem);
Console.WriteLine("string : {0}", resultStringWithItem);
Console.WriteLine("int : {0}", resultInt);
Console.WriteLine("char : {0}", resultChar);
Console.WriteLine("long : {0}", resultLong);
Console.WriteLine("double : {0}", resultDouble);
}
}
}
The above will produce following output:
string :
string : One
int : 0
char :
long : 0
double : 0
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,
public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source)
{
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
switch (list.Count)
{
case 0:
return default(TSource);
case 1:
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
return default(TSource);
}
TSource current = enumerator.Current;
if (!enumerator.MoveNext())
{
return current;
}
}
}
throw Error.MoreThanOneElement();
}
Go to the contents.
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.
public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count)
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,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>()
{
"One","Two","Three", "Four","Five"
};
var result = numbers.Skip(2);
result.ToList().ForEach(number => Console.WriteLine(number));
}
}
}
The program will produce following output,
Three
Four
Five
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 approximate code of the SkipIterator
is as below,
private static IEnumerable<TSource> SkipIterator<TSource>(
IEnumerable<TSource> source, int count)
{
using (IEnumerator<TSource> iteratorVariable0 = source.GetEnumerator())
{
while ((count > 0) && iteratorVariable0.MoveNext())
{
count--;
}
if (count <= 0)
{
while (iteratorVariable0.MoveNext())
{
yield return iteratorVariable0.Current;
}
}
}
}
Go to the contents.
SkipWhile
This extension method bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements. Read more.
The method signature of this extension method is as below,
public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
Let’s see an example of the SKipWhile
extension method which will help to understand of this extension method,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<string> numbers = new List<string>()
{
"One","Two","Three", "Four","Five"
};
var result = numbers.SkipWhile(number => number.Length == 3);
result.ToList().ForEach(number => Console.WriteLine(number));
}
}
}
The above program will produce the following output,
Three
Four
Five
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 approximate code for the SkipWhileIterator
will be as below,
private static IEnumerable<TSource> SkipWhileIterator<TSource>(
IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
bool iteratorVariable0 = false;
foreach (TSource iteratorVariable1 in source)
{
if (!iteratorVariable0 && !predicate(iteratorVariable1))
{
iteratorVariable0 = true;
}
if (iteratorVariable0)
{
yield return iteratorVariable1;
}
}
}
Go to the contents.
Sum
To sum all the items inside a list we can use this Sum
extension method. Read more The signature of those methods is below,
public static int Sum(this IEnumerable<int> source)
public static int Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, int> selector)
An example of the Min
Extension method is as below,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,2,3,4,5,6,7,8,9,10
};
Console.WriteLine("Sum of the numbers :{0}", numbers.Sum());
Console.WriteLine("Sum of the original numbers x2 :{0}",
numbers.Sum(x => x * 2));
}
}
}
The program will produce the following output,
Sum of the numbers :55
Sum of the original numbers x2 :110
To execute the first version of the Sum extension method used in the above program, CLR will do the following steps to perform the operation,
Step 1: The CLR will pass the original list as input to the Sum extension method.
Step 2: Inside the Sum
method it will loop through the list and perform the summation of each of the item and produced the result and return as output of the Sum.
Fig: Sum Extension method
The approximate of the Sum
method is as below,
public static int Sum(this IEnumerable<int> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
int num = 0;
foreach (int num2 in source)
{
num += num2;
}
return num;
}
To execute the second version of the Sum extension method CLR will execute following operations,
Step 1: The compiler will create a method <Main>b_1
using the anonymous method (x => x * 2)
code.
Note: When I decompiled the produced executable from the above program using ILDasm.exe, there will be a method:
.method private hidebysig static int32 <Main>b__1(int32 x) cil managed
{
.maxstack 2
.locals init (
[0] int32 CS$1$0000)
L_0000: ldarg.0
L_0001: ldc.i4.2
L_0002: mul
L_0003: stloc.0
L_0004: br.s L_0006
L_0006: ldloc.0
L_0007: ret
}
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,
Go to the contents.
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.
The signature of the ThenBy
extension methods is as below,
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(
this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(
this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
public static IOrderedEnumerable<TSource> ThenByDescending<TSource, TKey>(
this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
I wrote this following program to explain the ThenyBy
extension method,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<Person> persons = new List<Person>()
{
new Person(){ Name="Person F", Address= "Address of F", Id= 111116},
new Person(){ Name="Person G", Address= "Address of G", Id= 111117},
new Person(){ Name="Person C", Address= "Address of C", Id= 111113},
new Person(){ Name="Person B", Address= "Address of B", Id= 111112},
new Person(){ Name="Person D", Address= "Address of D", Id= 111114},
new Person(){ Name="Person A", Address= "Address of A", Id= 111111},
new Person(){ Name="Person E", Address= "Address of E", Id= 111115}
};
var result = persons.OrderBy(person => person.Id).ThenBy(person => person);
foreach (Person person in result)
{
Console.WriteLine("{0,-15} {1,-20}{2,-20}",
person.Name,
person.Address,
person.Id);
}
}
}
public class Person
{
public string Name
{
get;
set;
}
public string Address
{
get;
set;
}
public double Id
{
get;
set;
}
}
}
The above program will produce the following output,
Person A Address of A 111111
Person B Address of B 111112
Person C Address of C 111113
Person D Address of D 111114
Person E Address of E 111115
Person F Address of F 111116
Person G Address of G 111117
It will work as,
Step 1: Code: Approximate code for the ThenBy
method.
public static IOrderedEnumerable<TSource> ThenBy<TSource, TKey>(
this IOrderedEnumerable<TSource> source,
Func<TSource, TKey> keySelector)
{
return source.CreateOrderedEnumerable<TKey>(keySelector, null, false);
}
Step 2:
IOrderedEnumerable<TElement> IOrderedEnumerable<TElement>.CreateOrderedEnumerable<TKey>(
Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
return new OrderedEnumerable<TElement, TKey>(this.source, keySelector,
comparer, descending) { parent = (OrderedEnumerable<TElement>) this };
}
Step 2: The implementation of the Order
internal class OrderedEnumerable<TElement, TKey> : OrderedEnumerable<TElement>
{
internal IComparer<TKey> comparer;
internal bool descending;
internal Func<TElement, TKey> keySelector;
internal OrderedEnumerable<TElement> parent;
internal OrderedEnumerable(IEnumerable<TElement> source,
Func<TElement, TKey> keySelector,
IComparer<TKey> comparer,
bool descending)
{
base.source = source;
this.parent = null;
this.keySelector = keySelector;
this.comparer = (comparer != null) ? comparer : ((IComparer<TKey>) Comparer<TKey>.Default);
this.descending = descending;
}
internal override EnumerableSorter<TElement> GetEnumerableSorter(
EnumerableSorter<TElement> next)
{
EnumerableSorter<TElement> enumerableSorter = new
EnumerableSorter<TElement, TKey>(
this.keySelector,
this.comparer,
this.descending, next);
if (this.parent != null)
{
enumerableSorter = this.parent.GetEnumerableSorter(enumerableSorter);
}
return enumerableSorter;
}
}
Go to the contents.
It will create an array from the list. Following program will show the usage of the
ToArray()
method. The method signature is as below,
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
ToList<TSource>
has similar behavior but returns a List<T>
instead of an array.
Read more.
Let’s see an example of the ToArray()
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> firstList = new List<int>()
{
1,2,3,4
};
var result = firstList.ToArray();
result.ToList().ForEach(x => Console.WriteLine(x));
}
}
}
This program will produce the following output:
1
2
3
4
The CLR will execute the above as below,
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,
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)
{
Buffer<TSource> buffer = new Buffer<TSource>(source);
return buffer.ToArray();
}
The internal of the Buffer<TSource>
structure will be as below,
internal struct Buffer<TElement>
{
internal TElement[] items;
internal int count;
internal Buffer(IEnumerable<TElement> source)
{
TElement[] array = null;
int length = 0;
ICollection<TElement> i.= source as ICollection<TElement>;
if (i.!= null)
{
length = i..Count;
if (length > 0)
{
array = new TElement[length];
i..CopyTo(array, 0);
}
}
else
{
foreach (TElement local in source)
{
if (array == null)
{
array = new TElement[4];
}
else if (array.Length == length)
{
TElement[] destinationArray = new TElement[length * 2];
Array.Copy(array, 0, destinationArray, 0, length);
array = destinationArray;
}
array[length] = local;
length++;
}
}
this.items = array;
this.count = length;
}
}
Step 3: And finally when the CLR calls the ToArray
method, it will return:
internal TElement[] ToArray()
{
if (this.count == 0)
{
return new TElement[0];
}
if (this.items.Length == this.count)
{
return this.items;
}
TElement[] destinationArray = new TElement[this.count];
Array.Copy(this.items, 0, destinationArray, 0, this.count);
return destinationArray;
}
A copy of the items array as output of the ToArray
method.
Go to the contents.
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.
The signature of the ToDictionary
extension is as below:
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
Read more.
Let’s see an example which will help to understand this ToDictionary
method easily,
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<Person> persons = new List<Person>()
{
new Person(){ Name="Person A", Address= "Address of A", Id= 111111},
new Person(){ Name="Person B", Address= "Address of B", Id= 111112},
new Person(){ Name="Person C", Address= "Address of C", Id= 111113},
new Person(){ Name="Person D", Address= "Address of D", Id= 111114},
};
var result = persons.ToDictionary(person => person.Id);
foreach (KeyValuePair<double, Person> person in result)
{
Console.WriteLine("{0,-15} {1,-20}{2,-20}{3,-20}",
person.Key,
person.Value.Name,
person.Value.Address,
person.Value.Id);
}
}
}
public class Person
{
public string Name
{
get;
set;
}
public string Address
{
get;
set;
}
public double Id
{
get;
set;
}
}
}
The above program will produce the following output,
111111 Person A Address of A 111111
111112 Person B Address of B 111112
111113 Person C Address of C 111113
111114 Person D Address of D 111114
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,
public static Dictionary<tkey,> ToDictionary<tsource,>( this IEnumerable<tsource> source,
Func<tsource,> keySelector, Func<tsource,> elementSelector, IEqualityComparer<tkey> comparer)
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,
Fig: IdentityFunction
public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector)
{
return source.ToDictionary<TSource, TKey, TSource>(
keySelector, IdentityFunction<TSource>.Instance, null);
}
Step 2: When the CLR goes to the above method, this method call overloaded
ToDictionary
as below,
public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
Func<TSource, TElement> elementSelector,
IEqualityComparer<TKey> comparer)
{
Dictionary<TKey, TElement> dictionary = new Dictionary<TKey, TElement>(comparer);
foreach (TSource local in source)
{
dictionary.Add(keySelector(local), elementSelector(local));
}
return dictionary;
}
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.
Go to the contents.
ToList
It creates a List<T>
from an IEnumerable<T>
. Read more
The method signature for this extension method is as below,
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
To explain the working details of the ToList()
extension method let’s see an example which is
ToList()
to produce the result,
I wrote a small program to show the usage of the ToList( this IEnumerable<TSource> collection)
extension methods,
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> numbers = new List<int>()
{
1,2,3,4,5,6,7,8,9,10
};
var result = numbers.Where(x => x > 3).ToList();
result.ForEach(x => Console.Write("{0}\t", x));
Console.WriteLine();
}
}
}
The above program will produce following output as result,
4 5 6 7 8 9 10
So the CLR will execute the ToList()
as below,
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,
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
return new List<TSource>(source);
}
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,
public List(IEnumerable<T> collection)
{
ICollection<T> i. = collection as ICollection<T>;
if (i. != null)
{
int count = i..Count;
this._items = new T[count];
i..CopyTo(this._items, 0);
this._size = count;
}
else
{
this._size = 0;
this._items = new T[4];
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
this.Add(enumerator.Current);
}
}
}
}
Fig: ToList() extension method working details.
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,
public void Add(T item)
{
if (this._size == this._items.Length)
{
this.EnsureCapacity(this._size + 1);
}
this._items[this._size++] = item;
this._version++;
}
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.
Go to the contents.
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.
The signature of this extension method is as below,
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first, IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> resultSelector)
Read more
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
.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Chapter_5
{
class Program
{
static void Main(string[] args)
{
IList<int> firstList = new List<int>()
{
1,2,3,4
};
IList<string> secondList = new List<string>()
{
"One","Two","Three","Four"
};
var result = firstList.Zip(secondList, (x, y) => x + ":\t" + y);
result.ToList().ForEach(x => Console.WriteLine(x));
}
}
}
This program will produce following output as a result,
1: One
2: Two
3: Three
4: Four
So when the Compiler finds the Zip
method it will,
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,
.method private hidebysig static string '<Main>b__2'(int32 x,
string y) cil managed
{
.maxstack 3
.locals init ([0] string CS$1$0000)
IL_0000: ldarg.0
IL_0001: box [mscorlib]System.Int32
IL_0006: ldstr ":\t"
IL_000b: ldarg.1
IL_000c: call string [mscorlib]System.String::Concat(object,
object,
object)
IL_0011: stloc.0
IL_0012: br.s IL_0014
IL_0014: ldloc.0
IL_0015: ret
}
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.
The approximate code for the Zip extension is as below,
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> resultSelector)
{
return ZipIterator<TFirst, TSecond, TResult>(first, second, resultSelector);
}
private static IEnumerable<TResult> ZipIterator<TFirst, TSecond, TResult>(
IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> resultSelector)
{
using (IEnumerator<TFirst> iteratorVariable0 = first.GetEnumerator())
{
using (IEnumerator<TSecond> iteratorVariable1 = second.GetEnumerator())
{
while (iteratorVariable0.MoveNext() && iteratorVariable1.MoveNext())
{
yield return resultSelector(
iteratorVariable0.Current,
iteratorVariable1.Current);
}
}
}
}
Go to the contents.
Related articles
History
- Added Extension method working details in behind the scene.
- PDF file has been updated.
- Table of contents updated.
- External link has been added for the Min extension.
- Table of contents updated.
- PDF file has been removed.