0% found this document useful (0 votes)
44 views72 pages

LINQ

This is LINQ notes

Uploaded by

vickydasuri111
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
44 views72 pages

LINQ

This is LINQ notes

Uploaded by

vickydasuri111
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 72

1

LINQ (Language-Integrated Query)


Language-Integrated Query (LINQ) is a powerful set of technologies based on the integration of query
capabilities directly into the C# language. LINQ Queries are the first-class language construct in C# .NET, just
like classes, methods, events. The LINQ provides a consistent query experience to query objects (LINQ to
Objects), relational databases (LINQ to SQL), and XML (LINQ to XML).
LINQ (Language Integrated Query) is uniform query syntax in C# and VB.NET to retrieve data from different
sources and formats. It is integrated in C# or VB, thereby eliminating the mismatch between programming
languages and databases, as well as providing a single querying interface for different types of data sources.
For example, SQL is a Structured Query Language used to save and retrieve data from a database. In the same
way, LINQ is a structured query syntax built in C# and VB.NET to retrieve data from different types of data
sources such as collections, ADO.Net DataSet, XML Docs, web service and MS SQL Server and other databases.

LINQ queries return results as objects. It enables you to uses object-oriented approach on the result set and
not to worry about transforming different formats of results into objects.
The following example demonstrates a simple LINQ query that gets all strings from an array which contains 'a'.

Example: LINQ Query to Array


// Data source
string[] names = {"Bill", "Steve", "James", "Mohan" };

// LINQ Query
var myLinqQuery = from name in names
where name.Contains('a')
select name;

// Query execution
foreach(var name in myLinqQuery)
Console.Write(name + " "); //James Mohan
You will not get the result of a LINQ query until you execute it. LINQ query can be execute in multiple ways,
here we used foreach loop to execute our query stored in myLinqQuery. The foreach loop executes the query on
the data source and get the result and then iterates over the result set.
Thus, every LINQ query must query to some kind of data sources whether it can be array, collections, XML or
other databases. After writing LINQ query, it must be executed to get the result.
Why LINQ?
To understand why we should use LINQ, let's look at some examples. Suppose you want to find list of teenage
students from an array of Student objects.
Before C# 2.0, we had to use a 'foreach' or a 'for' loop to traverse the collection to find a particular object. For
example, we had to write the following code to find all Student objects from an array of Students where the
age is between 12 and 20 (for teenage 13 to 19):
2

Example: Use for loop to find elements from the collection in C# 1.0
class Student
{
public int StudentID { get; set; }
public String StudentName { get; set; }
public int Age { get; set; }
}

class Program
{
static void Main(string[] args)
{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18 },
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 },
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 },
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 },
new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 },
new Student() { StudentID = 6, StudentName = "Chris", Age = 17 },
new Student() { StudentID = 7, StudentName = "Rob",Age = 19 },
};

Student[] students = new Student[10];

int i = 0;

foreach (Student std in studentArray)


{
if (std.Age > 12 && std.Age < 20)
{
students[i] = std;
i++;
}
}
}
}
Use of for loop is cumbersome, not maintainable and readable. C# 2.0 introduced delegate, which can be used
to handle this kind of a scenario, as shown below.

Example: Use Delegates to Find Elements from the Collection in C# 2.0


delegate bool FindStudent(Student std);

class StudentExtension
{
public static Student[] where(Student[] stdArray, FindStudent del)
{
int i=0;
Student[] result = new Student[10];
foreach (Student std in stdArray)
if (del(std))
{
result[i] = std;
i++;
}

return result;
}
}

class Program
{
static void Main(string[] args)
{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
3

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,


new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 } ,
new Student() { StudentID = 6, StudentName = "Chris", Age = 17 } ,
new Student() { StudentID = 7, StudentName = "Rob",Age = 19 } ,
};

Student[] students = StudentExtension.where(studentArray, delegate(Student std){


return std.Age > 12 && std.Age < 20;
});
}
}
}
So, with C# 2.0, you got the advantage of delegate in finding students with any criteria. You don't have to
use a for loop to find students using different criteria. For example, you can use the same delegate function to
find a student whose StudentId is 5 or whose name is Bill, as below:
Student[] students = StudentExtension.where(studentArray, delegate(Student std) {
return std.StudentID == 5;
});

//Also, use another criteria using same delegate


Student[] students = StudentExtension.where(studentArray, delegate(Student std) {
return std.StudentName == "Bill";
});
LINQ API in .NET
We can write LINQ queries for the classes that implement IEnumerable<T> or IQueryable<T> interface.
The System.Linq namespace includes the following classes and interfaces require for LINQ queries.

LINQ API

System.Linq namespace is included by default when you add a new class in Visual Studio.
LINQ queries uses extension methods for classes that implement IEnumerable or IQueryable interface.
The Enumerable and Queryable are two static classes that contain extension methods to write LINQ queries.
LINQ Query Syntax
4

There are two basic ways to write a LINQ query to IEnumerable collection or IQueryable data sources.
1. Query Syntax or Query Expression Syntax
2. Method Syntax or Method Extension Syntax or Fluent
Query Syntax
Query syntax is similar to SQL (Structured Query Language) for the database. It is defined within the C# or VB
code.
LINQ Query Syntax:
from <range variable> in <IEnumerable<T> or IQueryable<T> Collection>

<Standard Query Operators> <lambda expression>

<select or groupBy operator> <result formation>


The LINQ query syntax starts with from keyword and ends with select keyword. The following is a sample LINQ
query that returns a collection of strings which contains a word "Tutorials".

Example: LINQ Query Syntax in C#


using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp10
{
internal class Program
{
static void Main(string[] args)
{
// string collection
IList<string> stringList = new List<string>() {
"C# Tutorials",
"VB.NET Tutorials",
"Learn C++",
"MVC Tutorials" ,
"Java"
};

// LINQ Query Syntax


var result = from s in stringList where s.Contains("Tutorials")select s;

foreach (var str in result)


{
Console.WriteLine(str);
}
}
}
}
Output
//C# Tutorials
//VB.NET Tutorials
//MVC Tutorials
The following figure shows the structure of LINQ query syntax.

LINQ Query Syntax


Query syntax starts with a From clause followed by a Range variable. The From clause is structured
like "From rangeVariableName in IEnumerablecollection". In English, this means, from each object in the
collection. It is similar to a foreach loop: foreach(Student s in studentList).
After the From clause, you can use different Standard Query Operators to filter, group, join elements of the
collection. There are around 50 Standard Query Operators available in LINQ. In the above figure, we have used
5

"where" operator (aka clause) followed by a condition. This condition is generally expressed using lambda
expression.
LINQ query syntax always ends with a Select or Group clause. The Select clause is used to shape the data. You
can select the whole object as it is or only some properties of it. In the above example, we selected the each
resulted string elements.
In the following example, we use LINQ query syntax to find out teenager students from the Student collection
(sequence).

Example: LINQ Query Syntax in C#


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp10
{
internal class Program
{
static void Main(string[] args)
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

// LINQ Query Syntax to find out teenager students


var teenAgerStudent = from s in studentList where s.Age > 12 && s.Age < 20 select s;
Console.WriteLine("Teen age Students:");

foreach (Student std in teenAgerStudent)


{
Console.WriteLine(std.StudentName);
}
}
}

internal class Student


{
public int StudentID { get; internal set; }
public string StudentName { get; internal set; }
public int Age { get; internal set; }
}

}
Output:
Teen age Students:
John
Bill
Ron
LINQ Method Syntax
In the previous section, you have learned about LINQ Query Syntax. Here, you will learn about Method syntax.
Method syntax (also known as fluent syntax) uses extension methods included in
the Enumerable or Queryable static class, similar to how you would call the extension method of any class.
The compiler converts query syntax into method syntax at compile time.
The following is a sample LINQ method syntax query that returns a collection of strings which contains a word
"Tutorials".
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp10
{
6

internal class Program


{
static void Main(string[] args)
{
// string collection
IList<string> stringList = new List<string>()
{
"C# Tutorials",
"VB.NET Tutorials",
"Learn C++",
"MVC Tutorials" ,
"Java"
};

// LINQ Method Syntax


var result = stringList.Where(s => s.Contains("Tutorials"));

foreach (var str in result)


{
Console.WriteLine(str);
}
}
}
}
Output
C# Tutorials
VB.NET Tutorials
MVC Tutorials

The following figure illustrates the structure of LINQ method syntax.

LINQ Method Syntax Structure


As you can see in the above figure, method syntax comprises of extension methods and Lambda expression.
The extension method Where() is defined in the Enumerable class.
If you check the signature of the Where extension method, you will find the Where method accepts
a predicate delegate as Func<Student, bool>. This means you can pass any delegate function that accepts a
Student object as an input parameter and returns a Boolean value as shown in the below figure. The lambda
expression works as a delegate passed in the Where clause. Learn lambda expression in the next section.
The following example shows how to use LINQ method syntax query with the IEnumerable<T> collection.
using System;
using System.Linq;
using System.Collections.Generic;

public class Program


{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

// LINQ Query Method to find out teenager students


var teenAgerStudent = studentList.Where(s => s.Age > 12 && s.Age < 20);
7

Console.WriteLine("Teen age Students:");

foreach(Student std in teenAgerStudent){


Console.WriteLine(std.StudentName);
}
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Teen age Students:
John
Bill
Ron

Anatomy of the Lambda Expression


C# 3.0(.NET 3.5) introduced the lambda expression along with LINQ. The lambda expression is a shorter way
of representing anonymous method using some special syntax.
For example, following anonymous method checks if student is teenager or not:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;

public class Program


{
delegate bool IsTeenAger(Student stud);

public static void Main()


{
IsTeenAger isTeenAger = delegate (Student s) { return s.Age > 12 && s.Age < 20; };

Student stud = new Student() { Age = 25 };

Console.WriteLine(isTeenAger(stud));
}
}
public class Student
{

public int Id { get; set; }


public string Name { get; set; }
public int Age { get; set; }
}
Output: False

Example: Lambda Expression in C#


public class Program
{
delegate bool IsTeenAger(Student stud);

public static void Main()


{
IsTeenAger isTeenAger = s => s.Age > 12 && s.Age < 20;

Student stud = new Student() { Age = 25 };

Console.WriteLine(isTeenAger(stud));
8

}
}

public class Student{

public int Id { get; set; }


public string Name { get; set; }
public int Age { get; set; }
}
Output
False

Standard Query Operators


Standard Query Operators in LINQ are actually extension methods for the IEnumerable<T> and
IQueryable<T> types. They are defined in the System.Linq.Enumerable and System.Linq.Queryable classes.
There are over 50 standard query operators available in LINQ that provide different functionalities like filtering,
sorting, grouping, aggregation, concatenation, etc.
Standard Query Operators in Query Syntax

Standard Query Operators in Query


Syntax
Standard Query Operators in Method Syntax

Standard Query Operators in Method Syntax


Standard query operators in query syntax is converted into extension methods at compile time. So both are
same.
Standard Query Operators can be classified based on the functionality they provide. The following table lists all
the classification of Standard Query Operators:

Classification Standard Query Operators


Filtering Where, OfType

Sorting OrderBy, OrderByDescending, ThenBy, ThenByDescending, Reverse

Grouping GroupBy, ToLookup

Join GroupJoin, Join

Projection Select, SelectMany

Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum

Quantifiers All, Any, Contains

Elements ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault


9

Classification Standard Query Operators


Set Distinct, Except, Intersect, Union

Partitioning Skip, SkipWhile, Take, TakeWhile

Concatenation Concat

Equality SequenceEqual

Generation DefaultEmpty, Empty, Range, Repeat

Conversion AsEnumerable, AsQueryable, Cast, ToArray, ToDictionary, ToList

Filtering Operator - Where


Filtering operators in LINQ filter the sequence (collection) based on some given criteria.
The following table lists all the filtering operators available in LINQ.
Filtering Operators Description
Where Returns values from the collection based on a predicate function.
OfType Returns values from the collection based on a specified type. However, it will depend on their ability to cast to a sp
Where
The Where operator (Linq extension method) filters the collection based on a given criteria expression and
returns a new collection. The criteria can be specified as lambda expression or Func delegate type.
The Where extension method has following two overloads. Both overload methods accepts a Func
delegate type parameter. One overload required Func<TSource,bool> input parameter and second overload
method required Func<TSource, int, bool> input parameter where int is for index:
Wmethod Overloads:
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);
Where clause in Query Syntax
The following query sample uses a Where operator to filter the students who is teen ager from the given
collection (sequence). It uses a lambda expression as a predicate function.
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

// LINQ Query Syntax to find out teenager students


var teenAgerStudent = from s in studentList where s.Age > 12 && s.Age < 20 select s;
Console.WriteLine("Teen age Students:");

foreach (Student std in teenAgerStudent)


{
Console.WriteLine(std.StudentName);
}
}
}

public class Student


{

public int StudentID { get; set; }


public string StudentName { get; set; }
10

public int Age { get; set; }

}
Output
Teen age Students:
John
Bill
Ron
In the above sample query, the lambda expression body s.Age > 12 && s.Age < 20 is passed as a predicate
function Func<TSource, bool> that evaluates every student in the collection.
Alternatively, you can also use a Func type delegate with an anonymous method to pass as a predicate
function as below (output would be the same):

Example: Where clause


public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

Func<Student, bool> isTeenAger = delegate (Student s)


{
return s.Age > 12 && s.Age < 20;
};

var filteredResult = from s in studentList where isTeenAger(s) select s;

foreach (var std in filteredResult)


Console.WriteLine(std.StudentName);
}
}

public class Student


{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

}
Output
John
Bill
Ron
Where extension method in Method Syntax
Unlike the query syntax, you need to pass whole lambda expression as a predicate function instead of just
body expression in LINQ method syntax.
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

// LINQ Query Method to find out teenager students


var teenAgerStudent = studentList.Where(s => s.Age > 12 && s.Age < 20);
11

Console.WriteLine("Teen age Students:");

foreach(Student std in teenAgerStudent){


Console.WriteLine(std.StudentName);
}
}
}
public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

}
Output:
Teen age Students:
John
Bill
Ron

As mentioned above, the Where extension method also have second overload that includes index of current
element in the collection. You can use that index in your logic if you need.

The following example uses the Where clause to filter out odd elements in the collection and return only even
elements. Please remember that index starts from zero.

public class Program

public static void Main()

// Student collection

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 13} ,

new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,

new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }

};

var filteredResult = studentList.Where((s, i) => {

if(i % 2 == 0) // if it is even element


12

return true;

return false;

});

foreach (var std in filteredResult)

Console.WriteLine(std.StudentName);

public class Student{

public int StudentID { get; set; }

public string StudentName { get; set; }

public int Age { get; set; }

}
Output
John
Bill
Ron
Multiple Where clause

You can call the Where() extension method more than one time in a single LINQ query.

Example: Multiple where clause in Query Syntax C#


var filteredResult = from s in studentList
where s.Age > 12
where s.Age < 20
select s;

Example: Multiple where clause in Method Syntax C#


var filteredResult = studentList.Where(s => s.Age > 12).Where(s => s.Age < 20);

Filtering Operator - OfType

The OfType operator filters the collection based on the ability to cast an element in a collection to a specified
type.
13

OfType in Query Syntax

Use OfType operator to filter the above collection based on each element's type
public class Program
{
public static void Main()
{
IList mixedList = new ArrayList();
mixedList.Add(0);
mixedList.Add("One");
mixedList.Add("Two");
mixedList.Add(3);
mixedList.Add(new Student() { StudentID = 1, StudentName = "Bill" });

var stringResult = from s in mixedList.OfType<string>()


select s;

var intResult = from s in mixedList.OfType<int>()


select s;

var stdResult = from s in mixedList.OfType<Student>()


select s;

foreach (var str in stringResult)


Console.WriteLine(str);
Console.WriteLine("------");
foreach (var integer in intResult)
Console.WriteLine(integer);

foreach (var std in stdResult)


Console.WriteLine(std.StudentName);

}
}

public class Student


{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

}
Output

One

Two

Bill
OfType in Method Syntax

You can use OfType<TResult>() extension method in linq method syntax as shown below.

Example: OfType in C#
var stringResult = mixedList.OfType<string>();

stringResult would contain following elements.


14

One

Two

Sorting Operators: OrderBy & OrderByDescending

A sorting operator arranges the elements of the collection in ascending or descending order. LINQ includes
following sorting operators.

Sorting Operator Description


OrderBy Sorts the elements in the collection based on specified fields in ascending or decending order.

OrderByDescending Sorts the collection based on specified fields in descending order. Only valid in method syntax.

ThenBy Only valid in method syntax. Used for second level sorting in ascending order.

ThenByDescending Only valid in method syntax. Used for second level sorting in descending order.

Reverse Only valid in method syntax. Sorts the collection in reverse order.

OrderBy

OrderBy sorts the values of a collection in ascending or descending order. It sorts the collection in ascending
order by default because ascending keyword is optional here. Use descending keyword to sort collection in
descending order.
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};

var orderByResult = from s in studentList


orderby s.StudentName //Sorts the studentList collection in ascending order
select s;

var orderByDescendingResult = from s in studentList //Sorts the studentList collection in descending order
orderby s.StudentName descending
select s;

Console.WriteLine("Ascending Order:");

foreach (var std in orderByResult)


Console.WriteLine(std.StudentName);

Console.WriteLine("Descending Order:");

foreach (var std in orderByDescendingResult)


Console.WriteLine(std.StudentName);

}
15

public class Student


{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

Output

Ascending Order:

Bill

John

Ram

Ron

Steve

Descending Order:

Steve

Ron

Ram

John

Bill
OrderBy in Method Syntax

OrderBy extension method has two overloads. First overload of OrderBy extension method accepts the Func
delegate type parameter. So you need to pass the lambda expression for the field based on which you want to
sort the collection.

The second overload method of OrderBy accepts object of IComparer along with Func delegate type to use
custom comparison for sorting.
OrderBy Overload Methods:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source,


Func<TSource, TKey> keySelector,
IComparer<TKey> comparer);

The following example sorts the studentList collection in ascending order of StudentName using OrderBy
extension method.

Example: OrderBy in Method Syntax C#


16

public class Program

public static void Main()

// Student collection

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,

new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,

new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }

};

var studentsInAscOrder = studentList.OrderBy(s => s.StudentName);

var studentsInDescOrder = studentList.OrderByDescending(s => s.StudentName);

Console.WriteLine("Ascending Order:");

foreach (var std in studentsInAscOrder)

Console.WriteLine(std.StudentName);

Console.WriteLine("Descending Order:");
17

foreach (var std in studentsInDescOrder)

Console.WriteLine(std.StudentName);

public class Student{

public int StudentID { get; set; }

public string StudentName { get; set; }

public int Age { get; set; }

Output

Ascending Order:
Bill
John
Ram
Ron
Steve
Descending Order:
Steve
Ron
Ram
John
Bill
Multiple Sorting

You can sort the collection on multiple fields seperated by comma. The given collection would be first sorted
based on the first field and then if value of first field would be the same for two elements then it would use
second field for sorting and so on.

Example: Multiple sorting in Query syntax C#

public class Program


{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
18

new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,


new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};

var multiSortingResult = from s in studentList orderby s.StudentName, s.Age select s;

foreach (var std in multiSortingResult)


Console.WriteLine("Name: {0}, Age {1}", std.StudentName, std.Age);

public class Student


{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

Output

Name: Bill, Age 25


Name: John, Age 18
Name: Ram, Age 20
Name: Ron, Age 19
Name: Steve, Age 15

Sorting Operators: ThenBy & ThenByDescending

The ThenBy and ThenByDescending extension methods are used for sorting on multiple fields.

The OrderBy() method sorts the collection in ascending order based on specified field. Use ThenBy() method
after OrderBy to sort the collection on another field in ascending order. Linq will first sort the collection based
on primary field which is specified by OrderBy method and then sort the resulted collection in ascending order
again based on secondary field specified by ThenBy method.

The same way, use ThenByDescending method to apply secondary sorting in descending order.

The following example shows how to use ThenBy and ThenByDescending method for second level sorting:
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};

var thenByResult = studentList.OrderBy(s => s.StudentName).ThenBy(s => s.Age);

var thenByDescResult = studentList.OrderBy(s => s.StudentName).ThenByDescending(s => s.Age);

Console.WriteLine("ThenBy:");

foreach (var std in thenByResult)


19

Console.WriteLine("Name: {0}, Age:{1}", std.StudentName, std.Age);

Console.WriteLine("ThenByDescending:");

foreach (var std in thenByDescResult)


Console.WriteLine("Name: {0}, Age:{1}", std.StudentName, std.Age);

public class Student


{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

Output

ThenBy:

Name: Bill, Age:25

Name: John, Age:18

Name: Ram, Age:20

Name: Ron, Age:19

Name: Steve, Age:15

ThenByDescending:

Name: Bill, Age:25

Name: John, Age:18

Name: Ram, Age:20

Name: Ron, Age:19

Name: Steve, Age:15

Grouping Operators: GroupBy & ToLookup

The grouping operators do the same thing as the GroupBy clause of SQL query. The grouping operators create
a group of elements based on the given key. This group is contained in a special type of collection that
implements an IGrouping<TKey,TSource> interface where TKey is a key value, on which the group has been
formed and TSource is the collection of elements that matches with the grouping key value.
Grouping Operators Description
GroupBy The GroupBy operator returns groups of elements based on some key value. Each group is represented by IGrouping<TKey, TElement> objec
ToLookup ToLookup is the same as GroupBy; the only difference is the execution of GroupBy is deferred whereas ToLookup execution is immediate.
20

GroupBy

The GroupBy operator returns a group of elements from the given collection based on some key value. Each
group is represented by IGrouping<TKey, TElement> object. Also, the GroupBy method has eight overload
methods, so you can use appropriate extension method based on your requirement in method syntax.
Note:
A LINQ query can end with a GroupBy or Select clause.

The result of GroupBy operators is a collection of groups. For example, GroupBy returns
IEnumerable<IGrouping<TKey,Student>> from the Student collection:

Retur
n type of GroupBy()
GroupBy in Query Syntax

The following example creates a groups of students who have same age. Students of the same age will be in
the same collection and each grouped collection will have a key and inner collection, where the key will be the
age and the inner collection will include students whose age is matched with a key.

public class Program

public static void Main()

// Student collection

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,

new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,

new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }

};

var groupedResult = from s in studentList


21

group s by s.Age;

//iterate each group

foreach (var ageGroup in groupedResult)

Console.WriteLine("Age Group: {0}", ageGroup.Key); //Each group has a key

foreach(Student s in ageGroup) // Each group has inner collection

Console.WriteLine("Student Name: {0}", s.StudentName);

public class Student{

public int StudentID { get; set; }

public string StudentName { get; set; }

public int Age { get; set; }

Output

Age Group: 18
Student Name: John
Student Name: Bill
Age Group: 21
Student Name: Steve
Student Name: Ron
Age Group: 20
Student Name: Ram
22

GroupBy in Method Syntax

The GroupBy() extension method works the same way in the method syntax. Specify the lambda expression for
key selector field name in GroupBy extension method.

Example: GroupBy in method syntax C#

public class Program

public static void Main()

// Student collection

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,

new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,

new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }

};

var groupedResult = studentList.GroupBy(s => s.Age);

foreach (var ageGroup in groupedResult)

Console.WriteLine("Age Group: {0}", ageGroup.Key); //Each group has a key

foreach(Student s in ageGroup) //Each group has a inner collection

Console.WriteLine("Student Name: {0}", s.StudentName);

}
23

public class Student{

public int StudentID { get; set; }

public string StudentName { get; set; }

public int Age { get; set; }

}
Output
Age Group: 18
Student Name: John
Student Name: Bill
Age Group: 21
Student Name: Steve
Student Name: Ron
Age Group: 20
Student Name: Ram

ToLookup

ToLookup is the same as GroupBy; the only difference is GroupBy execution is deferred, whereas ToLookup
execution is immediate. Also, ToLookup is only applicable in Method syntax. ToLookup is not supported in
the query syntax.

Example: ToLookup in method syntax C#


public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};

var lookupResult = studentList.ToLookup(s => s.Age);

foreach (var group in lookupResult)


{
Console.WriteLine("Age Group: {0}", group.Key); //Each group has a key

foreach(Student s in group) //Each group has a inner collection


Console.WriteLine("Student Name: {0}", s.StudentName);
}

}
24

}
public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

}
Output
Age Group: 18
Student Name: John
Student Name: Bill
Age Group: 21
Student Name: Steve
Student Name: Ron
Age Group: 20
Student Name: Ram

Joining Operator: Join

The joining operators joins the two sequences (collections) and produce a result.
Joining Operators Usage
Join The Join operator joins two sequences (collections) based on a key and returns a resulted sequence.
GroupJoin The GroupJoin operator joins two sequences based on keys and returns groups of sequences. It is like Left Outer Join of SQL.
Join

The Join operator operates on two collections, inner collection & outer collection. It returns a new collection
that contains elements from both the collections which satisfies specified expression. It is the same as inner
join of SQL.
Join in Method Syntax

The Join extension method has two overloads as shown below.

As you can see in the first overload method takes five input parameters (except the first 'this' parameter): 1)
outer 2) inner 3) outerKeySelector 4) innerKeySelector 5) resultSelector.

Let's take a simple example. The following example joins two string collection and return new collection that
includes matching strings in both the collection.

Example: Join operator C#

public class Program


{
public static void Main()
{
// Student collection
IList<string> strList1 = new List<string>() {
"One",
"Two",
"Three",
"Four"
};

IList<string> strList2 = new List<string>() {


"One",
"Two",
"Five",
"Six"
};
25

var innerJoinResult = strList1.Join(// outer sequence


strList2, // inner sequence
str1 => str1, // outerKeySelector
str2 => str2, // innerKeySelector
(str1, str2) => str1);

foreach (var str in innerJoinResult)


{
Console.WriteLine("{0} ", str);
}

}
}

Output
One
Two

The following example demonstrates LINQ Join query.

Example: Join Query C#

public class Program


{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18,
StandardID = 1 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21,
StandardID = 1 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18,
StandardID = 2 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20,
StandardID = 2 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};

IList<Standard> standardList = new List<Standard>() {


new Standard(){ StandardID = 1, StandardName="Standard 1"},
new Standard(){ StandardID = 2, StandardName="Standard 2"},
new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var innerJoinResult = studentList.Join(// outer sequence


standardList, // inner sequence
student => student.StandardID, // outerKeySelector
standard => standard.StandardID, // innerKeySelector
(student, standard) => new // result selector
{
StudentName = student.StudentName,
StandardName = standard.StandardName
});

foreach (var obj in innerJoinResult)


{

Console.WriteLine("{0} - {1}", obj.StudentName, obj.StandardName);


}

}
26

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
}

public class Standard{

public int StandardID { get; set; }


public string StandardName { get; set; }
}
Output
John - Standard 1
Steve - Standard 1
Bill - Standard 2
Ram - Standard 2

Join in Query Syntax

Join operator in query syntax works slightly different than method syntax. It requires outer sequence, inner
sequence, key selector and result selector. 'on' keyword is used for key selector where left side of 'equals'
operator is outerKeySelector and right side of 'equals' is innerKeySelector.

Syntax: Join in query syntax


from ... in outerSequence

join ... in innerSequence

on outerKey equals innerKey

select ...

The following example of Join operator in query syntax returns a collection of elements from studentList and
standardList if their Student.StandardID and Standard.StandardID is match.

Example: Join operator in query syntax C#


public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18,
StandardID = 1 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21,
StandardID = 1 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18,
StandardID = 2 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20,
StandardID = 2 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};

IList<Standard> standardList = new List<Standard>() {


new Standard(){ StandardID = 1, StandardName="Standard 1"},
new Standard(){ StandardID = 2, StandardName="Standard 2"},
new Standard(){ StandardID = 3, StandardName="Standard 3"}
};
27

var innerJoinResult = from s in studentList // outer sequence


join st in standardList //inner sequence
on s.StandardID equals st.StandardID // key
selector
select new { // result selector
StudentName =
s.StudentName,
StandardName =
st.StandardName
};

foreach (var obj in innerJoinResult)


{

Console.WriteLine("{0} - {1}", obj.StudentName, obj.StandardName);


}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
}

public class Standard{

public int StandardID { get; set; }


public string StandardName { get; set; }
}
Output
John - Standard 1
Steve - Standard 1
Bill - Standard 2
Ram - Standard 2

Joining Operator: GroupJoin

We have seen the Join operator in the previous section. The GroupJoin operator performs the same task as
Join operator except that GroupJoin returns a result in group based on specified group key. The GroupJoin
operator joins two sequences based on key and groups the result by matching key and then returns the
collection of grouped result and key.

GroupJoin requires same parameters as Join. GroupJoin has following two overload methods:
GroupJoin Overload Methods:
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter>
outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey>
innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);

public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter>


outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey>
innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, IEqualityComparer<TKey>
comparer);

As you can see in the first overload method takes five input parameters (except the first 'this' parameter): 1)
outer 2) inner 3) outerKeySelector 4) innerKeySelector 5) resultSelector. Please notice that resultSelector is of
Func delegate type that has second input parameter as IEnumerable type for inner sequence.
28

Now, let's understand GroupJoin using following Student and Standard class where Student class includes
StandardID that matches with StandardID of Standard class.

Example Classes
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18,
StandardID = 1 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21,
StandardID = 1 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18,
StandardID = 2 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20,
StandardID = 2 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};

IList<Standard> standardList = new List<Standard>() {


new Standard(){ StandardID = 1, StandardName="Standard 1"},
new Standard(){ StandardID = 2, StandardName="Standard 2"},
new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var groupJoin = standardList.GroupJoin(studentList, //inner sequence


std => std.StandardID, //outerKeySelector
s => s.StandardID, //innerKeySelector
(std, studentsGroup) => new // resultSelector
{
Students = studentsGroup,
StandarFulldName = std.StandardName
});

foreach (var item in groupJoin)


{
Console.WriteLine(item.StandarFulldName );

foreach(var stud in item.Students)


Console.WriteLine(stud.StudentName);
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
}

public class Standard{

public int StandardID { get; set; }


public string StandardName { get; set; }
}
Output
Standard 1
John
29

Steve
Standard 2
Bill
Ram
Standard 3

GroupJoin in Query Syntax

GroupJoin operator in query syntax works slightly different than method syntax. It requires an outer sequence,
inner sequence, key selector and result selector. 'on' keyword is used for key selector where the left side of
'equals' operator is the outerKeySelector and the right side of 'equals' is the innerKeySelector. Use
the into keyword to create the grouped collection.
Syntax: GroupJoin in Query Syntax
from ... in outerSequence

join ... in innerSequence

on outerKey equals innerKey

into groupedCollection

select ...

The following example demonstrates the GroupJoin in query syntax.

Example: GroupJoin Query Syntax C#


public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18,
StandardID = 1 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21,
StandardID = 1 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18,
StandardID = 2 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20,
StandardID = 2 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};

IList<Standard> standardList = new List<Standard>() {


new Standard(){ StandardID = 1, StandardName="Standard 1"},
new Standard(){ StandardID = 2, StandardName="Standard 2"},
new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var groupJoin = from std in standardList


join s in studentList
on std.StandardID equals s.StandardID
into studentGroup
select new {
Students = studentGroup ,
StandardName = std.StandardName
};

foreach (var item in groupJoin)


{
Console.WriteLine(item.StandardName );
30

foreach(var stud in item.Students)


Console.WriteLine(stud.StudentName);
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
}

public class Standard{

public int StandardID { get; set; }


public string StandardName { get; set; }
}
Output
Standard 1
John
Steve
Standard 2
Bill
Ram
Standard 3

Projection Operators: Select, SelectMany

There are two projection operators available in LINQ. 1) Select 2) SelectMany


Select

The Select operator always returns an IEnumerable collection which contains elements based on a
transformation function. It is similar to the Select clause of SQL that produces a flat result set.

Now, let's understand Select query operator using the following Student class.
public class Student{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}
Select in Query Syntax

LINQ query syntax must end with a Select or GroupBy clause. The following example demonstrates select
operator that returns a string collection of StudentName.

Example: Select in Query Syntax C#


public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John" } ,
new Student() { StudentID = 2, StudentName = "Moin" } ,
new Student() { StudentID = 3, StudentName = "Bill" } ,
new Student() { StudentID = 4, StudentName = "Ram" } ,
new Student() { StudentID = 5, StudentName = "Ron" }
};
31

var selectResult = from s in studentList select s.StudentName;

foreach(var name in selectResult){


Console.WriteLine(name);
}
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
}

Output
John
Moin
Bill
Ram
Ron
Select in Method Syntax

The Select operator is optional in method syntax. However, you can use it to shape the data. In the following
example, Select extension method returns a collection of anonymous object with the Name and Age property:

Example: Select in Method Syntax C#

public class Program

public static void Main()

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,

new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,

new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }

};

// returns collection of anonymous objects with Name and Age property

var selectResult = studentList.Select(s => new { Name = s.StudentName ,

Age = s.Age });

// iterate selectResult

foreach (var item in selectResult)

Console.WriteLine("Student Name: {0}, Age: {1}", item.Name, item.Age);


32

public class Student{

public int StudentID { get; set; }

public string StudentName { get; set; }

public int Age { get; set; }

Output

Student Name: John, Age: 13

Student Name: Moin, Age: 21

Student Name: Bill, Age: 18

Student Name: Ram, Age: 20

Student Name: Ron, Age: 15

Quantifier Operators

The quantifier operators evaluate elements of the sequence on some condition and return a boolean value to
indicate that some or all elements satisfy the condition.
Operator Description
All Checks if all the elements in a sequence satisfies the specified condition
Any Checks if any of the elements in a sequence satisfies the specified condition
Contains Checks if the sequence contains a specific element
All

The All operator evalutes each elements in the given collection on a specified condition and returns True if all
the elements satisfy a condition.

Example: All operator C#

public class Program

public static void Main()

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,


33

new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,

new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }

};

// checks whether all the students are teenagers

bool areAllStudentsTeenAger = studentList.All(s => s.Age > 12 && s.Age < 20);

Console.WriteLine(areAllStudentsTeenAger);

public class Student{

public int StudentID { get; set; }

public string StudentName { get; set; }

public int Age { get; set; }

Output

False
Any

Any checks whether any element satisfy given condition or not? In the following example, Any operation is
used to check whether any student is teen ager or not.

Example: Any operator C#

public class Program

public static void Main()

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,

new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,


34

new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }

};

// checks whether any of the students is teenager

bool isAnyStudentTeenAger = studentList.Any(s => s.Age > 12 && s.Age < 20);

Console.WriteLine(isAnyStudentTeenAger);

Output

True
Quantifier Operator: Contains

The Contains operator checks whether a specified element exists in the collection or not and returns a boolean.

The Contains() extension method has following two overloads. The first overload method requires a value to
check in the collection and the second overload method requires additional parameter of IEqualityComparer
type for custom equalality comparison.

As mentioned above, the Contains() extension method requires a value to check as a input parameter. Type of
a value must be same as type of generic collection. The following example of Contains checks whether 10
exists in the collection or not. Please notice that int is a type of generic collection.

Example: Contains operator C#

public class Program

public static void Main()

IList<int> intList = new List<int>() { 1, 2, 3, 4, 5 };

bool result = intList.Contains(10);

Console.WriteLine(result);

Output
35

False

Example two

public class Program

public static void Main()

IList<Student> studentList = new List<Student>() {

new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,

new Student() { StudentID = 2, StudentName = "Moin", Age = 15 } ,

new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,

new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,

new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }

};

Student std = new Student(){ StudentID =3, StudentName = "Bill"};

bool result = studentList.Contains(std, new StudentComparer());

Console.WriteLine(result);

public class Student{

public int StudentID { get; set; }

public string StudentName { get; set; }

public int Age { get; set; }

public class StudentComparer : IEqualityComparer<Student>

public bool Equals(Student x, Student y)


36

if (x.StudentID == y.StudentID &&

x.StudentName.ToLower() == y.StudentName.ToLower())

return true;

return false;

public int GetHashCode(Student obj)

return obj.GetHashCode();

Output

True

Aggregation Operators: Aggregate

The aggregation operators perform mathematical operations like Average, Aggregate, Count, Max, Min and
Sum, on the numeric property of the elements in the collection.
Method Description
Aggregate Performs a custom aggregation operation on the values in the collection.
Average calculates the average of the numeric items in the collection.
Count Counts the elements in a collection.
LongCount Counts the elements in a collection.
Max Finds the largest value in the collection.
Min Finds the smallest value in the collection.
Sum Calculates sum of the values in the collection.
Aggregate

The Aggregate method performs an accumulate operation. Aggregate extension method has the following
overload methods:
Aggregate() Overloads:
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func);

public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source,


TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func);

public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSource> source,


TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func,
Func<TAccumulate, TResult> resultSelector);
37

The following example demonstrates Aggregate method that returns comma seperated elements of the string
list.

public class Program

public static void Main()

IList<String> strList = new List<String>() { "One", "Two", "Three", "Four", "Five"};

var commaSeperatedString = strList.Aggregate((s1, s2) => s1 + ", " + s2);

Console.WriteLine(commaSeperatedString);

}
Output
One, Two, Three, Four, Five

Aggregate Method with Seed Value

The second overload method of Aggregate requires first parameter for seed value to accumulate. Second
parameter is Func type delegate:
TAccumulate Aggregate<TSource, TAccumulate>(TAccumulate seed, Func<TAccumulate, TSource, TAccumulate>
func); .

The following example uses string as a seed value in the Aggregate extension method.

Example: Aggregate with Seed Value C#


public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

string commaSeparatedStudentNames = studentList.Aggregate<Student, string>(


"Student Names: ", // seed value
(str, s) => str += s.StudentName + "," );

Console.WriteLine(commaSeparatedStudentNames);

}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
38

Output
Student Names: John,Moin,Bill,Ram,Ron,

Aggregate Method with Result Selector

Now, let's see third overload method that required the third parameter of the Func delegate expression for
result selector, so that you can formulate the result.

Example: Aggregate with Result Selector C#


public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

string commaSeparatedStudentNames = studentList.Aggregate<Student, string,string>(


String.Empty, // seed value
(str, s) => str += s.StudentName + ",", // returns result using seed value,
String.Empty goes to lambda expression as str
str => str.Substring(0,str.Length - 1 ));

Console.WriteLine(commaSeparatedStudentNames);

}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}

Output
John,Moin,Bill,Ram,Ron

Aggregation Operator: Average

Average extension method calculates the average of the numeric items in the collection. Average method
returns nullable or non-nullable decimal, double or float value.

The following example demonstrate Agerage method that returns average value of all the integers in the
collection.

Example: Average Method C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>(){ 10, 20, 30 };

var avg = intList.Average();

Console.WriteLine("Average: {0}", avg);


}
39

}
Output
Average: 20

You can specify an int, decimal, double or float property of a class as a lambda expression of which you want
to get an average value. The following example demonstrates Average method on the complex type.
Example: Average in Method Syntax C#
public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

var avgAge = studentList.Average(s => s.Age);

Console.WriteLine("Average Age of Student: {0}", avgAge);

}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Average Age of Student: 17.4

Aggregation Operator: Count

The Count operator returns the number of elements in the collection or number of elements that have satisfied
the given condition.

The Count() extension method has the following two overloads:


Count() Overloads:
int Count<TSource>();

int Count<TSource>(Func<TSource, bool> predicate);

The first overload method of Count returns the number of elements in the specified collection, whereas the
second overload method returns the number of elements which have satisfied the specified condition given as
lambda expression/predicate function.

The following example demonstrates Count() on primitive collection.

Example: Count() - C#
public class Program
{
public static void Main()
{
IList<int> intList = new List<int>(){ 10, 21, 30, 45, 50 };

var totalElements = intList.Count();

Console.WriteLine("Total Elements: {0}", totalElements);


40

var evenElements = intList.Count(i => i%2 == 0);

Console.WriteLine("Even Elements: {0}", evenElements);

}
}
Output
Total Elements: 5
Even Elements: 3

Example 2
public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 },
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 },
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 },
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

var totalStudents = studentList.Count();

Console.WriteLine("Total Students: {0}", totalStudents);

var adultStudents = studentList.Count(s => s.Age >= 18);

Console.WriteLine("Number of Adult Students: {0}", adultStudents );

}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Total Students: 5
Number of Adult Students: 3

Aggregation Operator: Max

The Max() method returns the largest numeric element from a collection.

The following example demonstrates Max() on primitive collection.

Example: Max method C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 10, 21, 30, 45, 50, 87 };

var largest = intList.Max();


41

Console.WriteLine("Largest Element: {0}", largest);

var largestEvenElements = intList.Max(i => {


if(i%2 == 0)
return i;

return 0;
});

Console.WriteLine("Largest Even Element: {0}", largestEvenElements );


}
}
Output
Largest Element: 87
Largest Even Element: 50

Max returns a result of any data type. The following example shows how you can find a student with the
longest name in the collection:

Example: Max() in C#

public class Program


{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Steve" , Age = 15 }
};

var studentWithLongName = studentList.Max();

Console.WriteLine("Student ID: {0}, Student Name: {1}", studentWithLongName.StudentID,


studentWithLongName.StudentName);

}
}

public class Student : IComparable<Student>


{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }

public int CompareTo(Student other)


{
if (this.StudentName.Length >= other.StudentName.Length)
return 1;

return 0;
}
}
Output
Student ID: 5, Student Name: Steve

Aggregation Operator: Sum


42

The Sum() method calculates the sum of numeric items in the collection.

The following example demonstrates Sum() on primitive collection.

Example: LINQ Sum() C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 10, 21, 30, 45, 50, 87 };

var total = intList.Sum();

Console.WriteLine("Sum: {0}", total);

var sumOfEvenElements = intList.Sum(i => {


if(i%2 == 0)
return i;

return 0;
});

Console.WriteLine("Sum of Even Element: {0}", sumOfEvenElements );


}
}
Output
Sum: 243
Sum of Even Element: 90

The following example calculates sum of all student's age and also number of adult students in a student
collection.

Example: LINQ Sum() - C#


public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Steve" , Age = 15 }
};

var sumOfAge = studentList.Sum(s => s.Age);

Console.WriteLine("Sum of all student's age: {0}", sumOfAge);

var totalAdults = studentList.Sum(s => {

if(s.Age >= 18)


return 1;
else
return 0;
});

Console.WriteLine("Total Adult Students: {0}", totalAdults);


}
}
43

public class Student


{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Sum of all student's age: 87
Total Adult Students: 3

Previous
Next

Element Operators: ElementAt, ElementAtOrDefault

Element operators return a particular element from a sequence (collection).

The following table lists all the Element operators in LINQ.


Element Operators
(Methods) Description
ElementAt Returns the element at a specified index in a collection
ElementAtOrDefault Returns the element at a specified index in a collection or a default value if the index is out of range.
First Returns the first element of a collection, or the first element that satisfies a condition.
FirstOrDefault Returns the first element of a collection, or the first element that satisfies a condition. Returns a default value if index is out of
range.
Last Returns the last element of a collection, or the last element that satisfies a condition
LastOrDefault Returns the last element of a collection, or the last element that satisfies a condition. Returns a default value if no such element
exists.
Single Returns the only element of a collection, or the only element that satisfies a condition.
SingleOrDefault Returns the only element of a collection, or the only element that satisfies a condition. Returns a default value if no such element
exists or the collection does not contain exactly one element.

The ElementAt() method returns an element from the specified index from a given collection. If the specified index is out of the range of a
collection then it will throw an Index out of range exception. Please note that index is a zero based index.

The ElementAtOrDefault() method also returns an element from the specified index from a collaction and if the specified index is out of
range of a collection then it will return a default value of the data type instead of throwing an error.

The following example demonstrates ElementAt and ElementAtOrDefault method on primitive collection.

Example: LINQ ElementAt() and ElementAtOrDefault() - C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 10, 21, 30, 45, 50, 87 };

IList<string> strList = new List<string>() { "One", "Two", null, "Four", "Five" };

Console.WriteLine("1st Element in intList: {0}", intList.ElementAt(0));


Console.WriteLine("1st Element in strList: {0}", strList.ElementAt(0));

Console.WriteLine("2nd Element in intList: {0}", intList.ElementAt(1));


Console.WriteLine("2nd Element in strList: {0}", strList.ElementAt(1));

Console.WriteLine("3rd Element in intList: {0}", intList.ElementAtOrDefault(2));


44

Console.WriteLine("3rd Element in strList: {0}", strList.ElementAtOrDefault(2));

Console.WriteLine("10th Element in intList: {0} - default int value",


intList.ElementAtOrDefault(9));
Console.WriteLine("10th Element in strList: {0} - default string value (null)",
strList.ElementAtOrDefault(9));

Console.WriteLine("intList.ElementAt(9) throws an exception: Index out of range");


Console.WriteLine("-------------------------------------------------------------");
Console.WriteLine(intList.ElementAt(9));

}
}
Output
1st Element in intList: 10
1st Element in strList: One
2nd Element in intList: 21
2nd Element in strList: Two
3rd Element in intList: 30
3rd Element in strList:
10th Element in intList: 0 - default int value
10th Element in strList: - default string value (null)
intList.ElementAt(9) throws an exception: Index out of range
-------------------------------------------------------------
Run-time exception (line 29): Index was out of range. Must be non-negative and less than the size
of the collection.
Parameter name: index

Stack Trace:

[System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than t
he size of the collection.
Parameter name: index]
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionRe
source resource)
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Linq.Enumerable.ElementAt[TSource](IEnumerable`1 source, Int32 index)
at P

Element Operators: First & FirstOrDefault

The First and FirstOrDefault method returns an element from the zeroth index in the collection i.e. the first
element. Also, it returns an element that satisfies the specified condition.
Element
Operators Description
First Returns the first element of a collection, or the first element that satisfies a condition.
FirstOrDefault Returns the first element of a collection, or the first element that satisfies a condition. Returns a default value if index is out of
range.

First and FirstOrDefault has two overload methods. The first overload method doesn't take any input parameter
and returns the first element in the collection. The second overload method takes the lambda expression as
predicate delegate to specify a condition and returns the first element that satisfies the specified condition.
First() Á FirstOrDefault() Overloads:
public static TSource First<TSource>(this IEnumerable<TSource> source);

public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source);

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool>


predicate);
45

The First() method returns the first element of a collection, or the first element that satisfies the specified
condition using lambda expression or Func delegate. If a given collection is empty or does not include any
element that satisfied the condition then it will throw InvalidOperation exception.

The FirstOrDefault() method does the same thing as First() method. The only difference is that it returns
default value of the data type of a collection if a collection is empty or doesn't find any element that satisfies
the condition.

The following example demonstrates First() method.

Example: LINQ First() - C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();

Console.WriteLine("1st Element in intList: {0}", intList.First());


Console.WriteLine("1st Even Element in intList: {0}", intList.First(i => i % 2 == 0));

Console.WriteLine("1st Element in strList: {0}", strList.First());

Console.WriteLine("emptyList.First() throws an InvalidOperationException");


Console.WriteLine("-------------------------------------------------------------");
Console.WriteLine(emptyList.First());

}
}
Output
1st Element in intList: 7
1st Even Element in intList: 10
1st Element in strList:
emptyList.First() throws an InvalidOperationException
-------------------------------------------------------------
Run-time exception (line 20): Sequence contains no elements

Stack Trace:

[System.InvalidOperationException: Sequence contains no elements]


at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Program.Main() :line 20

The following example demonstrates FirstOrDefault() method.

Example: LINQ FirstOrDefault() - C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();

Console.WriteLine("1st Element in intList: {0}", intList.FirstOrDefault());

Console.WriteLine("1st Even Element in intList: {0}", intList.FirstOrDefault(i => i %


2 == 0));

Console.WriteLine("1st Element in strList: {0}", strList.FirstOrDefault());


46

Console.WriteLine("1st Element in emptyList: {0}", emptyList.FirstOrDefault());

}
}
Output
1st Element in intList: 7
1st Even Element in intList: 10
1st Element in strList:
1st Element in emptyList:

Be careful while specifying condition in First() or FirstOrDefault(). First() will throw an exception if a collection
does not include any element that satisfies the specified condition or includes null element.

If a collection includes null element then FirstOrDefault() throws an exception while evaluting the specified
condition. The following example demonstrates this.

Example: LINQ First() & FirstOrDefault() - C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };

Console.WriteLine("1st Element which is greater than 250 in intList: {0}",


intList.First( i => i > 250));

//The following will throw an exception


//Console.WriteLine("1st Even Element in intList: {0}", strList.FirstOrDefault(s =>
s.Contains("T")));

}
}
Output
Run-time exception (line 12): Sequence contains no matching element

Stack Trace:

[System.InvalidOperationException: Sequence contains no matching element]


at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
at Program.Main() :line 12

Element Operators : Last & LastOrDefault

The Last() and LastOrDefault() extension methods returns the last element from the collection.
Element Operators Description
Last() Returns the last element from a collection, or the last element that satisfies a condition. Throws exception if no element found.
LastOrDefault() Returns the last element from a collection, or the last element that satisfies a condition. Returns a default value if no element found.
Method Signature:
public static TSource Last<TSource>(this IEnumerable<TSource> source);

public static TSource Last<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source);

public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool>


predicate);
47

The Last() method returns the last element from a collection, or the last element that satisfies the specified
condition using lambda expression or Func delegate. If a given collection is empty or does not include any
element that satisfied the condition then it will throw InvalidOperation exception.

The LastOrDefault() method does the same thing as the Last() method. The only difference is that it returns
default value of the data type of a collection if a collection is empty or doesn't find any element that satisfies
the condition.

Example: LINQ Last() - C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();

Console.WriteLine("Last Element in intList: {0}", intList.Last());


Console.WriteLine("Last Even Element in intList: {0}", intList.Last(i => i % 2 ==
0));

Console.WriteLine("Last Element in strList: {0}", strList.Last());

Console.WriteLine("emptyList.Last() throws an InvalidOperationException");


Console.WriteLine("-------------------------------------------------------------");
Console.WriteLine(emptyList.Last());

}
}
Output
Last Element in intList: 87
Last Even Element in intList: 50
Last Element in strList: Five
emptyList.Last() throws an InvalidOperationException
-------------------------------------------------------------
Run-time exception (line 20): Sequence contains no elements

Stack Trace:

[System.InvalidOperationException: Sequence contains no elements]


at System.Linq.Enumerable.Last[TSource](IEnumerable`1 source)
at Program.Main() :line 20

The following example demonstrates the LastOrDefault() method.

Example: LINQ LastOrDefault() - C#


public class Program
{
public static void Main()
{
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();

Console.WriteLine("Last Element in intList: {0}", intList.LastOrDefault());

Console.WriteLine("Last Even Element in intList: {0}",


intList.LastOrDefault(i => i % 2 == 0));

Console.WriteLine("Last Element in strList: {0}", strList.LastOrDefault());

Console.WriteLine("Last Element in emptyList: {0}", emptyList.LastOrDefault());


48

}
}
Output
Last Element in intList: 87
Last Even Element in intList: 50
Last Element in strList: Five
Last Element in emptyList:

Element Operators: Single & SingleOrDefault


Element
Operators Description
Single Returns the only element from a collection, or the only element that satisfies a condition. If Single() found no elements or more than one
elements in the collection then throws InvalidOperationException.
SingleOrDefault The same as Single, except that it returns a default value of a specified generic type, instead of throwing an exception if no element found
for the specified condition. However, it will thrown InvalidOperationException if it found more than one element for the specified
condition in the collection.

Single and SingleOrDefault have two overload methods. The first overload method doesn't take any input
parameter and returns a single element in the collection. The second overload method takes the lambda
expression as a predicate delegate that specifies the condition and returns a single element that satisfies the
specified condition.

Single() returns the only element from a collection, or the only element that satisfies the specified condition. If
a given collection includes no elements or more than one elements then Single() throws
InvalidOperationException.

The SingleOrDefault() method does the same thing as Single() method. The only difference is that it returns
default value of the data type of a collection if a collection is empty, includes more than one element or finds
no element or more than one element for the specified condition.

Example: Single in method syntax C#


public class Program
{
public static void Main()
{
IList<int> oneElementList = new List<int>() { 7 };
IList<int> intList = new List<int>() { 7, 10, 21, 30, 45, 50, 87 };
IList<string> strList = new List<string>() { null, "Two", "Three", "Four", "Five" };
IList<string> emptyList = new List<string>();

Console.WriteLine("The only element in oneElementList: {0}",


oneElementList.Single());
Console.WriteLine("The only element in oneElementList: {0}",
oneElementList.SingleOrDefault());

Console.WriteLine("Element in emptyList: {0}", emptyList.SingleOrDefault());

Console.WriteLine("The only element which is less than 10 in intList: {0}",


intList.Single(i => i < 10));

//Followings throw an exception


//Console.WriteLine("The only Element in intList: {0}", intList.Single());
//Console.WriteLine("The only Element in intList: {0}", intList.SingleOrDefault());
//Console.WriteLine("The only Element in emptyList: {0}", emptyList.Single());

}
}
Output
49

The only element in oneElementList: 7


The only element in oneElementList: 7
Element in emptyList:
The only element which is less than 10 in intList: 7

LINQ Equality Operator: SequenceEqual

There is only one equality operator: SequenceEqual. The SequenceEqual method checks whether the number of
elements, value of each element and order of elements in two collections are equal or not.

If the collection contains elements of primitive data types then it compares the values and number of
elements, whereas collection with complex type elements, checks the references of the objects. So, if the
objects have the same reference then they considered as equal otherwise they are considered not equal.

The following example demonstrates the SequenceEqual method with the collection of primitive data types.

Example: SequenceEqual in Method Syntax C#


public class Program
{
public static void Main()
{
IList<string> strList1 = new List<string>(){"One", "Two", "Three", "Four",
"Three"};

IList<string> strList2 = new List<string>(){"One", "Two", "Three", "Four",


"Three"};

bool isEqual = strList1.SequenceEqual(strList2);

Console.WriteLine(isEqual);

}
}
Output
True

The SequenceEqual extension method checks the references of two objects to determine whether two
sequences are equal or not. This may give wrong result. Consider following example:

Example: SequenceEqual in C#

public class Program


{
public static void Main()
{
Student std = new Student() { StudentID = 1, StudentName = "Bill" };

IList<Student> studentList1 = new List<Student>(){ std };

IList<Student> studentList2 = new List<Student>(){ std };

bool isStudentsEqual = studentList1.SequenceEqual(studentList2); // returns true

Console.WriteLine(isStudentsEqual);

Student std1 = new Student() { StudentID = 1, StudentName = "Bill" };

Student std2 = new Student() { StudentID = 1, StudentName = "Bill" };


50

IList<Student> studentList3 = new List<Student>(){ std1 };

IList<Student> studentList4 = new List<Student>(){ std2 };

isStudentsEqual = studentList3.SequenceEqual(studentList4); // returns false

Console.WriteLine(isStudentsEqual);

}
Output
True
False

To compare the values of two collection of complex type (reference type or object), you need to implement
IEqualityComperar<T> interface as shown below.

Example: IEqualityComparer C#:


public class Program
{
public static void Main()
{
IList<Student> studentList1 = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John" },
new Student() { StudentID = 2, StudentName = "Steve" },
new Student() { StudentID = 3, StudentName = "Bill" },
new Student() { StudentID = 4, StudentName = "Ram" },
new Student() { StudentID = 5, StudentName = "Ron" }
};

IList<Student> studentList2 = new List<Student>() {


new Student() { StudentID = 1, StudentName = "John" },
new Student() { StudentID = 2, StudentName = "Steve" },
new Student() { StudentID = 3, StudentName = "Bill" },
new Student() { StudentID = 4, StudentName = "Ram" },
new Student() { StudentID = 5, StudentName = "Ron" }
};

bool isEqual = studentList1.SequenceEqual(studentList2, new StudentComparer());

Console.WriteLine(isEqual);

}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
}

class StudentComparer : IEqualityComparer<Student>


{
public bool Equals(Student x, Student y)
{
if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentName.ToLower())
return true;

return false;
}
51

public int GetHashCode(Student obj)


{
return obj.GetHashCode();
}
}
Output
True

Concatenation Operator: Concat

The Concat() method appends two sequences of the same type and returns a new sequence (collection).

Example: Concat in C#
public class Program
{
public static void Main()
{
IList<string> collection1 = new List<string>() { "One", "Two", "Three" };
IList<string> collection2 = new List<string>() { "Five", "Six"};

var concateResult = collection1.Concat(collection2);

foreach (string str in concateResult)


Console.WriteLine(str);

}
}
Output
One
Two
Three
Five
Six

Generation Operator: DefaultIfEmpty

The DefaultIfEmpty() method returns a new collection with the default value if the given collection on which
DefaultIfEmpty() is invoked is empty.

Another overload method of DefaultIfEmpty() takes a value parameter that should be replaced with default
value.

Consider the following example.

Example: DefaultIfEmpty C#
public class Program
{
public static void Main()
{
IList<string> emptyList = new List<string>();

var newList1 = emptyList.DefaultIfEmpty();


var newList2 = emptyList.DefaultIfEmpty("None");

Console.WriteLine("Count: {0}", newList1.Count());


Console.WriteLine("Value: {0}", newList1.ElementAt(0));

Console.WriteLine("Count: {0}", newList2.Count());


Console.WriteLine("Value: {0}", newList2.ElementAt(0));
52

}
}
Output
Count: 1
Value:
Count: 1
Value: None

Generation Operators: Empty, Range, Repeat

LINQ includes generation operators DefaultIfEmpty, Empty, Range & Repeat. The Empty, Range & Repeat
methods are not extension methods for IEnumerable or IQueryable but they are simply static methods defined
in a static class Enumerable.
Method Description
Empty Returns an empty collection
Range Generates collection of IEnumerable<T> type with specified number of elements with sequential values, starting from first element.
Repeat Generates a collection of IEnumerable<T> type with specified number of elements and each element contains same specified value.
Empty

The Empty() method is not an extension method of IEnumerable or IQueryable like other LINQ methods. It is a
static method included in Enumerable static class. So, you can call it the same way as other static methods like
Enumerable.Empty<TResult>(). The Empty() method returns an empty collection of a specified type as shown
below.
public class Program
{
public static void Main()
{
var emptyCollection1 = Enumerable.Empty<string>();
var emptyCollection2 = Enumerable.Empty<Student>();

Console.WriteLine("Type: {0}", emptyCollection1.GetType().Name);


Console.WriteLine("Count: {0}", emptyCollection1.Count());

Console.WriteLine("Type: {0}", emptyCollection2.GetType().Name);


Console.WriteLine("Count: {0}", emptyCollection2.Count());

}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }

}
Output
Type: String[]
Count: 0
Type: Student[]
Count: 0

Range

The Range() method returns a collection of IEnumerable<T> type with specified number of elements and
sequential values starting from the first element.

Example: Enumerable.Range()
public class Program
53

{
public static void Main()
{
var intCollection = Enumerable.Range(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());

for(int i = 0; i < intCollection.Count(); i++)


Console.WriteLine("Value at index {0} : {1}", i, intCollection.ElementAt(i));

}
}
Output
Total Count: 10
Value at index 0 : 10
Value at index 1 : 11
Value at index 2 : 12
Value at index 3 : 13
Value at index 4 : 14
Value at index 5 : 15
Value at index 6 : 16
Value at index 7 : 17
Value at index 8 : 18
Value at index 9 : 19

Repeat

The Repeat() method generates a collection of IEnumerable<T> type with specified number of elements and
each element contains same specified value.

Example: Repeat
public class Program
{
public static void Main()
{
var intCollection = Enumerable.Repeat<int>(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());

for(int i = 0; i < intCollection.Count(); i++)


Console.WriteLine("Value at index {0} : {1}", i, intCollection.ElementAt(i));

}
}
Output
Total Count: 10
Value at index 0 : 10
Value at index 1 : 10
Value at index 2 : 10
Value at index 3 : 10
Value at index 4 : 10
Value at index 5 : 10
Value at index 6 : 10
Value at index 7 : 10
Value at index 8 : 10
Value at index 9 : 10

Set Operator: Distinct

The following table lists all Set operators available in LINQ.


Set Operators Usage
Distinct Returns distinct values from a collection.
Except Returns the difference between two sequences, which means the elements of one collection that do not appear in the second collection.
Intersect Returns the intersection of two sequences, which means elements that appear in both the collections.
54

Set Operators Usage


Union Returns unique elements from two sequences, which means unique elements that appear in either of the two sequences.

The following figure shows how each set operators works on the collections:

LINQ
Set operators
Distinct

The Distinct extension method returns a new collection of unique elements from the given collection.

Example: Distinct C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Two",
"Three" };

IList<int> intList = new List<int>(){ 1, 2, 3, 2, 4, 4, 3, 5 };

var distinctList1 = strList.Distinct();

foreach(var str in distinctList1)


Console.WriteLine(str);

var distinctList2 = intList.Distinct();

foreach(var i in distinctList2)
Console.WriteLine(i);

}
}
Output
One
Two
55

Three
1
2
3
4
5

The Distinct extension method doesn't compare values of complex type objects. You need to
implement IEqualityComparer<T> interface in order to compare the values of complex types. In the following
example, StudentComparer class implements IEqualityComparer<Student> to compare Student< objects.

Example: Implement IEqualityComparer in C#


public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};

var distinctStudents = studentList.Distinct(new StudentComparer());

foreach(var std in distinctStudents)


Console.WriteLine(std.StudentName);

}
}

public class Student


{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}

public class StudentComparer : IEqualityComparer<Student>


{
public bool Equals(Student x, Student y)
{
if (x.StudentID == y.StudentID
&& x.StudentName.ToLower() == y.StudentName.ToLower() )
return true;

return false;
}

public int GetHashCode(Student obj)


{
return obj.StudentID.GetHashCode();
}
}
Output
John
Steve
Bill
Ron
56

LINQ: Except

The Except() method requires two collections. It returns a new collection with elements from the first collection
which do not exist in the second collection (parameter collection).

Example: Except in method syntax C#


public class Program
{
public static void Main()
{
IList<string> strList1 = new List<string>(){"One", "Two", "Three", "Four",
"Five" };
IList<string> strList2 = new List<string>(){"Four", "Five", "Six", "Seven",
"Eight"};

var result = strList1.Except(strList2);

foreach(string str in result)


Console.WriteLine(str);
}
}
Output
One
Two
Three

Set Operator: Intersect

The Intersect extension method requires two collections. It returns a new collection that includes common
elements that exists in both the collection. Consider the following example.

Example: Intersect in method syntax C#


public class Program
{
public static void Main()
{
IList<string> strList1 = new List<string>() { "One", "Two", "Three", "Four",
"Five" };
IList<string> strList2 = new List<string>() { "Four", "Five", "Six", "Seven",
"Eight"};

var result = strList1.Intersect(strList2);

foreach(string str in result)


Console.WriteLine(str);
}
}
Output
Four
Five

The Intersect extension method doesn't return the correct result for the collection of complex types. You need
to implement IEqualityComparer interface in order to get the correct result from Intersect method.

Implement IEqualityComparer interface for Student class as shown below:

Example: Use IEqualityComparer with Intersect in C#

public class Program


{
57

public static void Main()


{
IList<Student> studentList1 = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};

IList<Student> studentList2 = new List<Student>() {


new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 } ,
new Student() { StudentID = 6, StudentName = "Ram" , Age = 29 }
};

var resultedCol = studentList1.Intersect(studentList2,new StudentComparer());

foreach(Student std in resultedCol)


Console.WriteLine(std.StudentName);
}
}

public class Student


{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}

public class StudentComparer : IEqualityComparer<Student>


{
public bool Equals(Student x, Student y)
{
if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentName.ToLower())
return true;

return false;
}

public int GetHashCode(Student obj)


{
return obj.StudentID.GetHashCode();
}
}
Output
Bill
Ron

The Intersect operator is Not Supported in C# & VB.Net Query syntax. However, you can use the Intersect
method on a query variable or wrap whole query into brackets and then call Intersect().

The following figure shows how each set operators works on the collections:
58

Set Operator: Union

The Union extension method requires two collections and returns a new collection that includes distinct
elements from both the collections. Consider the following example.

Example: Union() in C#
public class Program
{
public static void Main()
{
IList<string> strList1 = new List<string>() { "One", "Two", "three", "Four" };
IList<string> strList2 = new List<string>() { "Two", "THREE", "Four", "Five" };

var result = strList1.Union(strList2);

foreach(string str in result)


Console.WriteLine(str);
}
}
Output
One
Two
three
Four
THREE
Five

Partitioning Operators: Skip & SkipWhile

Partitioning operators split the sequence (collection) into two parts and return one of the parts.
Method Description
Skip Skips elements up to a specified position starting from the first element in a sequence.
59

Method Description
SkipWhile Skips elements based on a condition until an element does not satisfy the condition. If the first element itself doesn't satisfy the condition, it then skips 0 ele
sequence.
Take Takes elements up to a specified position starting from the first element in a sequence.
TakeWhile Returns elements from the first element until an element does not satisfy the condition. If the first element itself doesn't satisfy the condition then returns a
Skip

The Skip() method skips the specified number of element starting from first element and returns rest of the
elements.

Example: Skip() - C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Four", "Five" };

var result = strList.Skip(2);

foreach(var str in result)


Console.WriteLine(str);

}
}

Output
Three
Four
Five
Skip Operator in Query Syntax

The Skip & SkipWhile operator is Not Supported in C# query syntax. However, you can use Skip/SkipWhile
method on a query variable or wrap whole query into brackets and then call Skip/SkipWhile.

The following example demonstrates skip operator in query syntax - VB.NET

Example: Skip operator in VB.Net


Dim skipResult = From s In studentList
Skip 3
Select s
SkipWhile

As the name suggests, the SkipWhile() extension method in LINQ skip elements in the collection till the
specified condition is true. It returns a new collection that includes all the remaining elements once the
specified condition becomes false for any element.

The SkipWhile() method has two overload methods. One method accepts the predicate of Func<TSource,
bool> type and other overload method accepts the predicate Func<TSource, int, bool> type that pass the
index of an element.

In the following example, SkipWhile() method skips all elements till it finds a string whose length is equal or
more than 4 characters.

Example: SkipWhile in C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>() {
"One",
60

"Two",
"Three",
"Four",
"Five",
"Six" };

var result = strList.SkipWhile(s => s.Length < 4);

foreach(string str in result)


Console.WriteLine(str);

}
}

Output
Three
Four
Five
Six

Partitioning Operators: Take & TakeWhile

Partitioning operators split the sequence (collection) into two parts and returns one of the parts.

The Take() extension method returns the specified number of elements starting from the first element.

Example: Take() in C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Four",
"Five" };

var newList = strList.Take(2);

foreach(var str in newList)


Console.WriteLine(str);
}
}

Output
One
Two

TakeWhile

The TakeWhile() extension method returns elements from the given collection until the specified condition is
true. If the first element itself doesn't satisfy the condition then returns an empty collection.

The TakeWhile method has two overload methods. One method accepts the predicate of Func<TSource,
bool> type and the other overload method accepts the predicate Func<TSource, int, bool> type that passes
the index of element.

In the following example, TakeWhile() method returns a new collection that includes all the elements till it finds
a string whose length less than 4 characters.

Example: TakeWhile in C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "Three", "Four", "Five", "Hundred" };
61

var newList = strList.TakeWhile(s => s.Length > 4);

foreach(var str in newList)


Console.WriteLine(str);

}
}
Output
Three

In the above example, TakeWhile() includes only first element because second string element does not
satisfied the condition.

TakeWhile also passes an index of current element in predicate function. Following example of TakeWhile
method takes elements till length of string element is greater than it's index

Example: TakeWhile in C#:


public class Program
{
public static void Main()
{
IList<string> strList = new List<string>() {
"One",
"Two",
"Three",
"Four",
"Five",
"Six" };

var resultList = strList.TakeWhile((s, i) => s.Length > i);

foreach(string str in resultList)


Console.WriteLine(str);

}
}
Output
One
Two
Three
Four

Conversion Operators

The Conversion operators in LINQ are useful in converting the type of the elements in a sequence (collection).
There are three types of conversion operators: As operators (AsEnumerable and AsQueryable), To operators
(ToArray, ToDictionary, ToList and ToLookup), and Casting operators (Cast and OfType).

The following table lists all the conversion operators.

Method Description
AsEnumerable Returns the input sequence as IEnumerable<t>

AsQueryable Converts IEnumerable to IQueryable, to simulate a remote query provider

Cast Coverts a non-generic collection to a generic collection (IEnumerable to IEnumerable<T>)

OfType Filters a collection based on a specified type

ToArray Converts a collection to an array


62

Method Description
ToDictionary Puts elements into a Dictionary based on key selector function

ToList Converts collection to List

ToLookup Groups elements into an Lookup<TKey,TElement>

AsEnumerable & AsQueryable

The AsEnumerable and AsQueryable methods cast or convert a source object to IEnumerable<T> or
IQueryable<T> respectively.

Consider the following example: (courtesy: Jon Skeet)

Example: AsEnumerable & AsQueryable operator in C#:

public class Program


{
static void ReportTypeProperties<T>(T obj)
{
Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
Console.WriteLine("Actual type: {0}", obj.GetType().Name);
}

public static void Main()


{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 } ,
};

ReportTypeProperties( studentArray);
ReportTypeProperties(studentArray.AsEnumerable());
ReportTypeProperties(studentArray.AsQueryable());
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Compile-time type: Student[]
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
Compile-time type: IQueryable`1
Actual type: EnumerableQuery`1

Cast

Cast does the same thing as AsEnumerable<T>. It cast the source object into IEnumerable<T>.

Example: Cast operator in C#


public class Program
{
static void ReportTypeProperties<T>(T obj)
63

{
Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
Console.WriteLine("Actual type: {0}", obj.GetType().Name);
}

public static void Main()


{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 } ,
};

ReportTypeProperties(studentArray);
ReportTypeProperties(studentArray.Cast<Student>());
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Compile-time type: Student[]
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]

To Operators: ToArray(), ToList(), ToDictionary()

As the name suggests, ToArray(), ToList(), ToDictionary() method converts a source object into an array, List
or Dictionary respectively.

To operators force the execution of the query. It forces the remote query provider to execute a query and get
the result from the underlying data source e.g. SQL Server database.
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>() {
"One",
"Two",
"Three",
"Four",
"Three"
};

Console.WriteLine("strList type: {0}", strList.GetType().Name);

string[] strArray = strList.ToArray<string>();// converts List to Array

Console.WriteLine("strArray type: {0}", strArray.GetType().Name);

IList<string> newList = strArray.ToList<string>(); // converts array into list

Console.WriteLine("newList type: {0}", newList.GetType().Name);

}
}
64

Output
strList type: List`1
strArray type: String[]
newList type: List`1

Expression in LINQ

The lambda Expression can be assigned to the Func or Action type delegates to process over in-memory
collections. The .NET compiler converts the lambda expression assigned to Func or Action type delegate into
executable code at compile time.

LINQ introduced the new type called Expression that represents strongly typed lambda expression. It means
lambda expression can also be assigned to Expression<TDelegate> type. The .NET compiler converts the
lambda expression which is assigned to Expression<TDelegate> into an Expression tree instead of executable
code. This expression tree is used by remote LINQ query providers as a data structure to build a runtime query
out of it (such as LINQ-to-SQL, EntityFramework or any other LINQ query provider that implements
IQueryable<T> interface).

The following figure illustrates differences when the lambda expression assigned to the Func or Action delegate
and the Expression in LINQ.

Expression and Func

We will learn Expression tree in the next section but first, let's see how to define and invoke an Expression.
Define an Expression

Take the reference of System.Linq.Expressions namespace and use an Expression<TDelegate> class to define
an Expression. Expression<TDelegate> requires delegate type Func or Action.

For example, you can assign lambda expression to the isTeenAger variable of Func type delegate, as shown
below:

Example: Define Func delegate for an expression in C#

public class Student


{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}

Func<Student, bool> isTeenAger = s => s.Age > 12 && s.Age < 20;
Invoke an Expression

You can invoke the delegate wrapped by an Expression the same way as a delegate, but first you need to
compile it using the Compile() method. Compile() returns delegateof Func or Action type so that you can
invoke it like a delegate.

Example: Invoke Expression in C#


public class Program
{
public static void Main()
{
65

Expression<Func<Student, bool>> isTeenAgerExpr = s => s.Age > 12 && s.Age <


20;

//compile Expression using Compile method to invoke it as Delegate


Func<Student, bool> isTeenAger = isTeenAgerExpr.Compile();

//Invoke
bool result = isTeenAger(new Student(){ StudentID = 1, StudentName = "Steve",
Age = 20});

Console.WriteLine(result);
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
False

Expression Tree

You have learned about the Expression in the previous section. Now, let's learn about the Expresion tree here.

Expression tree as name suggests is nothing but expressions arranged in a tree-like data structure. Each node
in an expression tree is an expression. For example, an expression tree can be used to represent mathematical
formula x < y where x, < and y will be represented as an expression and arranged in the tree like structure.

Expression tree is an in-memory representation of a lambda expression. It holds the actual elements of the
query, not the result of the query.

The expression tree makes the structure of the lambda expression transparent and explicit. You can interact
with the data in the expression tree just as you can with any other data structure.

For example, consider the following isTeenAgerExpr expression:

Example: Expression in C#
public class Program
{
public static void Main()
{
ParameterExpression pe = Expression.Parameter(typeof(Student), "s");

MemberExpression me = Expression.Property(pe, "Age");

ConstantExpression constant = Expression.Constant(18, typeof(int));

BinaryExpression body = Expression.GreaterThanOrEqual(me, constant);

var ExpressionTree = Expression.Lambda<Func<Student, bool>>(body, new[]


{ pe });

Console.WriteLine("Expression Tree: {0}", ExpressionTree);

Console.WriteLine("Expression Tree Body: {0}", ExpressionTree.Body);


66

Console.WriteLine("Number of Parameters in Expression Tree: {0}",


ExpressionTree.Parameters.Count);

Console.WriteLine("Parameters in Expression Tree: {0}",


ExpressionTree.Parameters[0]);

}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Expression Tree: s => (s.Age >= 18)
Expression Tree Body: (s.Age >= 18)
Number of Parameters in Expression Tree: 1
Parameters in Expression Tree: s

Why Expression Tree?

We have seen in the previous section that the lambda expression assigned to Func<T> compiles into
executable code and the lambda expression assigned to Expression<TDelegate> type compiles into
Expression tree.

Executable code excutes in the same application domain to process over in-memory collection. Enumerable
static classes contain extension methods for in-memory collections that
implements IEnumerable<T> interface e.g. List<T>, Dictionary<T>, etc. The Extension methods in an
Enumerable class accept a predicate parameter of Func type delegate. For example, the Where extension
method accepts Func<TSource, bool> predicate. It then compiles it into IL (Intermediate Language) to
process over in-memory collections that are in the same AppDomain.

The following image shows Where extension method in Enumerable class includes Func delegate as a
parameter:

Func
delegate in Where

Func delegate is a raw executable code, so if you debug the code, you will find that the Func delegate will be
represented as opaque code. You cannot see its parameters, return type and body:

Func
delegate in debug mode

Func delegate is for in-memory collections because it will be processed in the same AppDomain, but what
about remote LINQ query providers like LINQ-to-SQL, EntityFramework or other third party products that
provides LINQ capabilities? How would they parse lambda expression that has been compiled into raw
executable code to know about the parameters, return type of lambda expression and build runtime query to
process further? The answer is Expression tree.
67

Expression<TDelegate> is compiled into a data structure called an expression tree.

If you debug the code, Expression delegate will be represented as shown below:

Expr
ession Tree in debug mode

Now you can see the difference between a normal delegate and an Expression. An expression tree is
transparent. You can retrieve a parameter, return type and body expression information from the expression,
as below:

Example: Expression Tree in C#


public class Program
{
public static void Main()
{
Expression<Func<Student, bool>> isTeenAgerExpr = s => s.Age > 12 && s.Age <
20;

var parameters = isTeenAgerExpr.Parameters;

Console.WriteLine("Expression: {0}", isTeenAgerExpr);

Console.WriteLine("Expression Type: {0}", isTeenAgerExpr.NodeType);

foreach (var param in parameters)


{
Console.WriteLine("Parameter Name: {0}", param.Name);
Console.WriteLine("Parameter Type: {0}", param.Type.Name );
}

var bodyExpr = isTeenAgerExpr.Body as BinaryExpression;

Console.WriteLine("Left side of body expression: {0}", bodyExpr.Left);


Console.WriteLine("Binary Expression Type: {0}", bodyExpr.NodeType);
Console.WriteLine("Right side of body expression: {0}", bodyExpr.Right);
Console.WriteLine("Return Type: {0}", isTeenAgerExpr.ReturnType);
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
Expression: s => ((s.Age > 12) AndAlso (s.Age < 20))
Expression Type: Lambda
Parameter Name: s
Parameter Type: Student
Left side of body expression: (s.Age > 12)
Binary Expression Type: AndAlso
Right side of body expression: (s.Age < 20)
Return Type: System.Boolean

LINQ query for LINQ-to-SQL or Entity Framework is not executed in the same app domain. For example, the
following LINQ query for Entity Framework is never actually executed inside your program:
68

Example: LINQ Query in C#


var query = from s in dbContext.Students
where s.Age >= 18
select s;

It is first translated into an SQL statement and then executed on the database server.

The code found in a query expression has to be translated into an SQL query that can be sent to another
process as a string. For LINQ-to-SQL or Entity Frameworks, that process happens to be an SQL server
database. It is obviously going to be much easier to translate a data structure such as an expression tree into
SQL than it is to translate raw IL or executable code into SQL because, as you have seen, it is easy to retrieve
information from an expression.

Expression trees were created for the task of converting code such as a query expression into a string that can
be passed to some other process and executed there.

Queryable static class includes extension methods that accept a predicate parameter of Expression type. This
predicate expression will be converted into an Expression Tree and then will be passed to the remote LINQ
provider as a data structure so that the provider can build an appropriate query from the expression tree and
execute the query.

Expr
ession Tree Process

Deferred Execution of LINQ Query

Deferred execution means that the evaluation of an expression is delayed until its realized value is actually
required. It greatly improves performance by avoiding unnecessary execution.

Deferred execution is applicable on any in-memory collection as well as remote LINQ providers like LINQ-to-
SQL, LINQ-to-Entities, LINQ-to-XML, etc.

Let's understand deferred execution using the following example:


69

Deferred Execution

In the above example, you can see the query is materialized and executed when you iterate using the foreach
loop. This is called deferred execution. LINQ processes the studentList collection when you actually access each
object from the collection and do something with it.
Deferred Execution returns the Latest Data

To check whether deferred execution returns the latest data each time, add one more teen ager student after
the foreach loop and check the teenager student list:

As you can see, the second foreach loop executes the query again and returns the latest data. Deferred
execution re-evaluates on each execution; this is called lazy evaluation. This is one of the major advantages
of deferred execution: it always gives you the latest data.
Implementing Deferred Execution

You can implement deferred execution for your custom extension methods for IEnumerable using
the yield keyword of C#.

For example, you can implement custom extension method GetTeenAgerStudents for IEnumerable that returns
a list of all students who are teenagers.
public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 12 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};

var teenAgerStudents = from s in studentList.GetTeenAgerStudents()

select s;

foreach (Student teenStudent in teenAgerStudents)


Console.WriteLine("Student Name: {0}", teenStudent.StudentName);
}
70

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}

public static class EnumerableExtensionMethods


{
public static IEnumerable<Student> GetTeenAgerStudents(this IEnumerable<Student> source)
{

foreach (Student std in source)


{
Console.WriteLine("Accessing student {0}", std.StudentName);

if (std.Age > 12 && std.Age < 20)


yield return std;
}
}
}
Output
Accessing student John
Student Name: John
Accessing student Steve
Student Name: Steve
Accessing student Bill
Student Name: Bill
Accessing student Ram
Accessing student Ron

Immediate Execution of LINQ Query

Immediate execution is the reverse of deferred execution. It forces the LINQ query to execute and gets the
result immediately. The 'To' conversion operators execute the given query and give the result immediately.
Method Syntax

In the following example, ToList() extension method executes the query immediately and returns the result.

C#: Immediate Execution


IList<Student> teenAgerStudents =
studentList.Where(s => s.age > 12 && s.age < 20).ToList();
Query Syntax

C#:
var teenAgerStudents = from s in studentList
where s.age > 12 && s.age < 20
select s;

The above query will not execute immediately. You won't find any result as shown below:

Im
mediate Execution

Query Syntax doesn't support 'To' operators but can use ToList(), ToArray() or ToDictionary() for immediate
execution as below:
71

C#:
IList<Student> teenAgerStudents = (from s in studentList
where s.age > 12 && s.age < 20
select s).ToList();

let keyword

The 'let' keyword is useful in query syntax. It projects a new range variable, allows re-use of the expression
and makes the query more readable.

For example, you can compare string values and select the lowercase string value as shown below:

Example: let in LINQ query - C#


public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 12 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};

var lowercaseStudentNames = from s in studentList


let lowercaseStudentName = s.StudentName.ToLower()
where lowercaseStudentName.StartsWith("r")
select lowercaseStudentName;

foreach (var name in lowercaseStudentNames)


Console.WriteLine(name);
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }
}
Output
ram
ron

LINQ - into Keyword

Use into keyword in LINQ query to form a group or to continue a query after a select clause.

Example: into keyword in LINQ


public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
72

new Student() { StudentID = 2, StudentName = "Moin", Age =


21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

var teenAgerStudents = from s in studentList


where s.Age > 12 && s.Age < 20
select s
into teenStudents
where
teenStudents.StudentName.StartsWith("B")
select teenStudents;

foreach(Student std in teenAgerStudents){


Console.WriteLine(std.StudentName);
}
}
}

public class Student{

public int StudentID { get; set; }


public string StudentName { get; set; }
public int Age { get; set; }

Output
Bill

You might also like