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
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.
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.
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);
}
}
}
}
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.
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
}
Any
This extension method determines whether any element of a sequence exists or satisfies a condition provided as predicate.
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;
}
Average
The
Average
extension method calculates the average of a sequence of numeric values.
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.
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#.
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.
Contains
The
Contains
extension method determines whether a sequence contains a specified element.
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;
}
Count
This count extension method returns the number of elements in a sequence.
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)
.
DefaultIfEmpty
This extension method returns the elements of an
IEnumerable<T>
, or a default valued singleton collection if the sequence is empty.
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;
}
}
Distinct
This extension method returns distinct elements from a sequence.
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;
}
}
}
ElementAt
This extension method returns the element at a specified index in a sequence.
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.
Empty
Empty extension method returns an empty
IEnumerable<T>
that has the specified type argument.
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,
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
}
Except
The
Except
method can be used to remove a list of items from another. It produces the set difference of two sequences.
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,
First
It returns the first element of a sequence.
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;
}
}
}
FirstOrDefault
It returns the first element of a sequence, or a default value if no element is found.
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);
}
Union
The
Union
method will union (denoted as ?) of a collection of sets is the set of all distinct elements in the collection. 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;
}
}
Intersect
It produces the set intersection of two sequences.
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;
}
}
Last
It returns the last element of a sequence.
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;
}
LastOrDefault
It returns the last element of a sequence, or a default value if no element is found.
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;
}
LongCount
It returns an Int64 that represents the number of elements in a sequence.
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;
}
Max
In .NET, five overloaded
Max
extension methods have been defined in the
Enumerable
class.
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.
Min
This extension method will find out the minimum of the list. 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.
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.
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;
}
}
}
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)
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++;
}
}
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.
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++;
}
}
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.
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--;
}
}
Single
This extension method returns a single, specific element of a sequence.
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 .
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();
}
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.
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;
}
}
}
}
SkipWhile
This extension method bypasses elements in a sequence as long as a
specified condition is true and then returns the remaining elements.
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;
}
}
}
Sum
To sum all the items inside a list we can use this
Sum
extension method. 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,
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.
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;
}
}
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.
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.
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)
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.
ToList
It creates a
List<T>
from an
IEnumerable<T>
.
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 T
oList()
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.
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)
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);
}
}
}
}