Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
62 views145 pages

What Is LINQ PDF

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 145

What is LINQ?

LINQ (Language Integrated Query) is uniform query syntax in C# and VB.NET


used to save and retrieve data from different sources. 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 used to save and retrieve data from different types of data sources
like an Object Collection, SQL server database, XML, web service etc.

LINQ always works with objects so you can use the same basic coding patterns
to query and transform data in XML documents, SQL databases, ADO.NET
Datasets, .NET collections, and any other format for which a LINQ provider is
available.

LINQ Usage

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.

1|Pag e
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):

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);

2|Pag e
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 } ,
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 st


d){
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";

3|Pag e
});

The C# team felt that they still needed to make the code even more compact and
readable. So they introduced the extension method, lambda expression,
expression tree, anonymous type and query expression in C# 3.0. You can use
these features of C# 3.0, which are building blocks of LINQ to query to the
different types of collection and get the resulted element(s) in a single statement.

The example below shows how you can use LINQ query with lambda expression
to find a particular student(s) from the student collection.

C# 3.0 onwards:

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 } ,
};

// Use LINQ to find teenager students


Student[] teenAgerStudents = studentArray.Where(s => s.age > 12 && s.age < 20
).ToArray();

// Use LINQ to find first student whose name is Bill


Student bill = studentArray.Where(s => s.StudentName == "Bill").FirstOrDefaul
t();

// Use LINQ to find student whose StudentID is 5


Student student5 = studentArray.Where(s => s.StudentID == 5).FirstOrDefault()
;
}
}

As you can see in the above example, we specify different criteria using LINQ
operator and lambda expression in a single statement. Thus, LINQ makes code
more compact and readable and it can also be used to query different data
sources. For example, if you have a student table in a database instead of an
array of student objects as above, you can still use the same query to find
students using the Entity Framework.

4|Pag e
Advantages of LINQ:
 Familiar language: Developers don’t have to learn a new query language

for each type of data source or data format.

 Less coding: It reduces the amount of code to be written as compared

with a more traditional approach.

 Readable code: LINQ makes the code more readable so other developers

can easily understand and maintain it.

 Standardized way of querying multiple data sources: The same LINQ

syntax can be used to query multiple data sources.

 Compile time safety of queries: It provides type checking of objects at

compile time.

 IntelliSense Support: LINQ provides IntelliSense for generic collections.

 Shaping data: You can retrieve data in different shapes.

LINQ API
LINQ is nothing but the collection of extension methods. System.Linq namespace
includes the necessary classes & interfaces for
LINQ. Enumerable and Queryable are two main static classes of LINQ API that
contain extension methods for LINQ.

System.Linq namespace is included by default when you add a new class in Visual
Studio, so that you can use LINQ by default.

5|Pag e
Enumerable:
Enumerable class includes extension methods forIEnumerable<T> interface.
Basically all the collection types which is included
in System.Collections.Generic namespaces e.g. List<T>, Dictionary<T>,
SortedList<T>, Queue<T>, HashSet<T>, LinkedList<T> etc.

The following figure illustrates that the extension methods included in Enumerable
class can be used with generic collection in C# or VB.Net.

IEnumerable<T> extension methods in Enumerable class

Queryable:
The Queryable class includes extension methods for IQueryable<t> interface.
IQueryable<T> is used to provide querying capabilities against a specific data
source where the type of the data is known. For example, Entity Framework api
implements IQueryable<T> interface to support LINQ queries with underlaying
database like SQL Server.

Also, there are APIs available to access third party data; for example, LINQ to
Amazon provides the ability to use LINQ with Amazon web services to search for
books and other items by implementing IQueryable interface.

The following figure illustrates that the extension methods included in Queryable
class can be used with various native or third party data providers.

6|Pag e
IQueryable extension methods in Queryable class

The following images shows extension methods included in


static System.Linq.Enumerable class.

Enumerable Class

The following images shows extension methods included in


static System.Linq.Queryable class.

7|Pag e
Queryable Class

You can see all the extension methods in visual studio by opening Object Explorer
(press Ctrl +Alt + j) and search for Enumerable or Queryable.

Points to Remember :
1. Use System.Linq namespace to use LINQ.
2. LINQ api includes two main static class Enumerable & Queryable.
3. The static Enumerable class includes extension methods for classes that
implements IEnumerable<T> interface.
4. IEnumerable<T> type of collections are in-memory collection like List,
Dictionary, SortedList, Queue, HashSet, LinkedList
5. The static Queryable class includes extension methods for classes that
implements IQueryable<T> interface
6. Remote query provider implements IQueryable<T>. eg. Linq-to-SQL,
LINQ-to-Amazon etc.

LINQ Syntax
There are two basic ways to write a LINQ query:

8|Pag e
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 a database. It is
defined within the C# or VB code.

LINQ Query Syntax:

from <range variable> in <collection>

<filter, joining, grouping, aggregate operators etc.> <lambda expression>

<select or groupBy operator> <formulate the result>

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 etc. There are around 50 Standard Query Operators available in LINQ.
In the above figure, we have used "where" operator (aka clause) followed by a
lambda expression body. (We will see lambda expression in detail in the next
section.)

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

9|Pag e
properties of it. In the above example, we selected the whole student object as
it is, but you can also write: select s.StudentName, this will only return Enumerable
of StudentName string.

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#

// 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;

Example: LINQ Query Syntax in VB.Net

// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

// LINQ Query Syntax to find out teenager students


Dim teenAgerStudents As IList(Of Student) = (From s In studentList _
Where s.Age > 12 And s.Age < 20 _
Select s).ToList()

Next, let's learn what the method syntax is.

10 | P a g e
Points to Remember :
1. As name suggest, Query Syntax is same like SQL (Structure Query
Language) syntax.
2. Query Syntax starts with from clause and can be end
with Select orGroupBy clause.
3. Use various other opertors like filtering, joining, grouping, sorting operators
to construct the desired result.
4. Implicitly typed variable - var can be used to hold the result of the LINQ
query.

LINQ Method Syntax


In the previous section, you have learned about LINQ Query Syntax. Here, you
will learn about Method syntax.

The compiler converts query syntax into method syntax at compile time.

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 following figure illustrates the structure of LINQ method syntax.

LINQ Method Syntax Structure

11 | P a g e
As you can see in the above figure, method syntax comprises of extension
methods and Lambda expression. The extension methods Where and ToList are
defined in the Enumerable class.

If you check the signature of the Where extension method, you will find the Where
method accepts apredicate 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.

Func delegate in Where

The following example shows how to use LINQ method syntax query with the
IEnumerable<T> collection.

Example: Method Syntax in C#

// 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 Method Syntax to find out teenager students


var teenAgerStudents = studentList.Where(s => s.Age > 12 && s.Age < 20)
.ToList<Student>();

Example: Method Syntax in VB.Net

// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},

12 | P a g e
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

// LINQ Method Syntax to find out teenager students


Dim teenAgerStudents As IList(Of Student) = studentList.Where(Function(s) s.Age > 12
And s.Age < 20)
.ToList()

Points to Remember :
1. As name suggest, Method Syntax is like calling extension method.
2. LINQ Method Syntax aka Fluent syntax because it allows series of
extension methods call.
3. Implicitly typed variable - var can be used to hold the result of the LINQ
query.

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 methods using some
special syntax.

For example, following anonymous method checks if student is teenager or not:

Anonymous method in C#:

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

Anonymous method in VB.Net:

Dim isStudentTeenAger = Function(s As Student) As Boolean


Return s.Age > 12 And s.Age < 20
End Function

13 | P a g e
The above anonymous method can be represented using a Lambda Expression in
C# and VB.Net as below:

Lambda Expression in C#:

s => s.Age > 12 && s.Age < 20

Lambda Expression in VB.Net:

Function(s) s.Age > 12 And s.Age < 20

Let's see how the lambda expression evolved from the following anonymous
method.

Anonymous method in C#:

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

The Lambda expression evolves from anonymous method by first removing the
delegate keyword and parameter type and adding a lambda operator:

Lambda Expression from Anonymous Method

The above lambda expression is absolutely valid, but we don't need the curly
braces, return and semicolon if we have only one statement that returns a value.
So we can eliminate it.

Also, we can remove parenthesis (), if we have only one parameter.

14 | P a g e
Lambda Expression from Anonymous Method

Thus, we got the lambda expression: s => s.Age > 12 && s.Age < 20 where s is a
parameter, => is the lambda operator and s.Age > 12 && s.Age < 20 is the body
expression:

Lambda Expression Structure in C#

Same way we got lambda expression in VB.Net can be written as below:

Lambda Expression Structure in VB.Net

Note :VB.Net doesn't support lambda operator =>

Lambda Expression with Multiple parameters:


You can wrap the parameters in parenthesis if you need to pass more than one
parameter, as below:

Example: Specify multiple parameters in lambda expression C#

(s, youngAge) => s.Age >= youngage;

You can also give type of each parameters if parameters are confusing:

15 | P a g e
Example: Specify parameter type in lambda expression C#

(Student s,int youngAge) => s.Age >= youngage;

Example: Specify multiple parameters in lambda expression VB.Net

Function(s, youngAge) s.Age >= youngAge

Lambd expression without any parameter:


It is not necessary to have atleast one parameter in a lambda expression. The
lambda expression can be specify without any parameter also.

Example: Lambda expression with zero parameter.

() => Console.WriteLine("Parameter less lambda expression")

Multiple statements in body expression:


You can wrap expressions in curly braces if you want to have more than one
statement in the body:

Example: Lambda expression C#

(s, youngAge) =>


{
Console.WriteLine("Lambda expression with multiple statements in the body");

Return s.Age >= youngAge;


}

Example: Lambda expression VB.Net

Function(s , youngAge)

Console.WriteLine("Lambda expression with multiple statements in the body")


Return s.Age >= youngAge

End Function

16 | P a g e
Local variable in Lambda Expression body:
You can declare a variable in the expression body to use it anywhere in the
expression body, as below:

Example: Lambda expression C#

s =>
{
int youngAge = 18;

Console.WriteLine("Lambda expression with multiple statements in the body");

return s.Age >= youngAge;


}
Example: Lambda expression VB.Net

Function(s)

Dim youngAge As Integer = 18

Console.WriteLine("Lambda expression with multiple statements in the body")

Return s.Age >= youngAge

End Function
You can invoke lambda expression as you invoke delegates. Learn how to invoke
lambda expression in the next section.

Points to Remember:
1. Lambda Expression is a shorter way of representing anonymous method.
2. Lambda Expression syntax: parameters => body expression
3. Lambda Expression can have zero parameter.
4. Lambda Expression can have multiple parameters in parenthesis ().
5. Lambda Expression can have multiple statements in body expression in
curly brackets {}.

17 | P a g e
Invoke the Lambda Expression:
As you have seen in the previous section, the lambda expression is a shorter way
of representing an anonymous method. An anonymous method can be created
using delegate, which can be invoked in the same way as a function. So, a lambda
expression can be assigned to a compatible delegate type and be invoked like a
delegate.

Consider the following lambda expression that determines whether a student is a


teenager or not.

Example: Lambda expression C#

s => s.age > 12 && s.age < 20;

To invoke the above lambda expression, first of all create a delegate that accepts
a paramter of Student type, returns a boolean value and then assigns the lambda
expression, shown above, to the delegate type as shown below. Then the delegate
type variable with () operator must be used to invoke it.

Example: Invoke lambda expression in C#

delegate bool isTeenAger(Student student);

isTeenAger isStudentTeen = s => s.age > 12 && s.age < 20;

Student std = new Student() { age = 21 };

isStudentTeen(std);// returns false

Instead of creating a custom delegate type (isTeenAger) as shown above, you


can use built-in delegate types Func<> and Action<>.

Func Delegate type:


Use the Func<> delegate when you want to return something from a lambda
expression. The last parameter type in a Func<> delegate is the return type and
rest are input parameters. Visit Func delegate section of C# tutorials to know
more about it.

Consider the following lambda expression to find out whether a student is a


teenager or not.

Example: Lambda expression assigned to Func delegate in C#

18 | P a g e
Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;

Student std = new Student() { age = 21 };

bool isTeen = isStudentTeenAger(std);// returns false

Example: Lamda expression assigned to Func delegate in VB.Net

Dim isStudentTeenAger As Func(Of Student, Boolean) = Function(s) s.Age > 12 And s.Age
< 20

Dim mystd As New Student With {.Age = 21}

Dim isTeen As Boolean = isStudentTeenAger(mystd) // returns false

In the above example, the Func delegate expects the first input parameter to be
of Student type and the return type to be boolean. The lambda expression s =>
s.age > 12 && s.age < 20 satisfies the Func<Student, bool> delegate requirement,
as shown below:

Func
delegate with Lambda Expression

The Func<> delegate shown above, would turn out to be a function as shown
below.

C#:

bool isStudentTeenAger(Student s)
{
return s.Age > 12 && s.Age < 20;
}

Action delegate type:


Unlike the Func delegate, an Action delegate can only have input parameters. Use
the Action delegate type when you don't need to return any value from lambda
expression.

19 | P a g e
Example: Lamda expression assigned to Action delegate in C#

Action<Student> PrintStudentDetail = s => Console.WriteLine("Name: {0}, Age: {1} ", s


.StudentName, s.Age);

Student std = new Student(){ StudentName = "Bill", Age=21};

PrintStudentDetail(std);//output: Name: Bill, Age: 21

Example: Lamda expression assigned to Action delegate in VB.Net

Dim printStudentDetail As Action(Of Student) = Sub(s) Console.WriteLine("Name: {0}, A


ge: {1} ", s.StudentName, s.Age)

Dim mystd As New Student With {.StudentName = "Bill", .Age = 21}

printStudentDetail(mystd)//output: Name: Bill, Age: 21

You can pass a lambda expression of Func or Action delegate type to a LINQ
query. Enumerable static class for LINQ includes Where extension method
for IEnumerable<T> that accepts a predicate of Func<TSource,bool> . So, the Where()
extension method for IEnumerable<Student> collection is required to
pass Func<Student,bool>, as shown below:

Func delegate parameter in Where extension method

So now, you can pass the lambda expression assigned to the Func delegate to
the Where() extension method in the method syntax as shown below:

Example: Func delegate in LINQ Method Syntax

IList<Student> studentList = new List<Student>(){...};

Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;

var teenStudents = studentList.Where(isStudentTeenAger).ToList<Student>();

Example: Func delegate in LINQ Query Syntax


20 | P a g e
IList<Student> studentList = new List<Student>(){...};

Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;

var teenStudents = from s in studentList


where isStudentTeenAger(s)
select s;

You can follow the same method in VB.Net to pass Func delegate.

Points to Remember:
1. Lambda Expression can be assigned to Func or Action delegate.
2. Lambda Expression can be invoked in a similar way to delegate.

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.Queryableclasses. 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

21 | P a g e
Standard Query Operators in Method Syntax:

Standard Query Operators in Method Syntax

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

Set Distinct, Except, Intersect, Union

Partitioning Skip, SkipWhile, Take, TakeWhile

22 | P a g e
Classification Standard Query Operators

Concatenation Concat

Equality SequenceEqual

Generation DefaultEmpty, Empty, Range, Repeat

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

Learn each Standard Query Operators in the next few sections.

Filtering Operators - 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
ability to cast to a specified type.

Where
The Where operator (Linq extension method) filters the collection based on a
given criteria. It accepts a predicate as a parameter.

The Where extension method has following two overloads. One overload
required Func<TSource,bool> input parameter and second overload method
required Func<TSource, int, bool> input parameter where int is for index:
23 | P a g e
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, F
unc<TSource, bool> predicate);

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, F


unc<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.

Example: Where clause - LINQ query syntax in C#

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 filteredResult = from s in studentList


where s.Age > 12 && s.Age < 20
select s.StudentName;

Example: Where clause - LINQ query syntax in VB.Net

Dim studentList = New List(Of Student) From {


New Student() With {.StudentID = 1, .StudentName = "John", .Age =
18},
New Student() With {.StudentID = 2, .StudentName = "Steve", .Age =
15},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age =
25},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 2
0},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 1
9}
}

Dim filteredResult = From s In studentList


Where s.Age > 12 And s.Age < 20
Select s.StudentName

24 | P a g e
In the above example, filteredResult will include following students after query
execution.

John

Steve

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):

Exapmle: Where clause

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;

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.

Example: Where in method syntax in C#

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

Example: Where in method syntax in VB.Net

Dim filteredResult = studentList.Where(Function(s) s.Age > 12 And s.Age < 20 )

25 | P a g e
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.

Example: Linq - Where extension method in C#

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 filteredResult = studentList.Where((s, i) => {


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

return false;
});

foreach (var std in filteredResult)


Console.WriteLine(std.StudentName);

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#

26 | P a g e
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);

Points to Remember :
1. Where is used for filtering the collection based on given criteria.
2. Where extension method has two overload methods. Use a second overload
method to know the index of current element in the collection.
3. Method Syntax requires the whole lambda expression in Where extension
method whereas Query syntax requires only expression body.
4. Multiple Where extension methods are valid in a single LINQ query.

Learn another filtering operator - OfType in the next section.

Filtering Operator - OfType


The OfType operator filters the collection based on the ability to cast to a specified
type.

OfType in Query Syntax:


Use OfType operator to filter the above collection based on each element's type

Example: OfType operator in C#

IList mixedList = new ArrayList();


mixedList.Add(0);
mixedList.Add("One");
mixedList.Add("Two");
mixedList.Add(3);

27 | P a g e
mixedList.Add(new Student() { StudentID = 1, StudentName = "Bill" });

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


select s;

Example: OfType operator in VB.Net:

Dim stringResult = From s In mixedList.OfType(Of String)()

The above sample queries will return items whose type is string in the mixedList.
stringResult contains following elements after execution:

One

Two

OfType can also filter the collection by a class type. The following example returns
items whose type is Student:

Example: OfType

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 students = from itm in mixedList.OfType<Student>()


select itm.StudentName;

The students variable shown above, will contain the following students after
execution:

Bill

28 | P a g e
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>();

Example: OfType in VB.Net

Dim stringResult = mixedList.OfType(Of String)

stringResult would contain following elements.

One

Two

Points to Remember :
1. The Where operator filters the collection based on a predicate function.
2. The OfType operator filters the collection based on a given type
3. Where and OfType extension methods can be called multiple times in a
single LINQ query.

Sorting Operators: OrderBy &


OrderByDescending

29 | P a g e
A sorting operator arranges the elements of the collection in ascending or
descending order.

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 in Query Syntax:


OrderBy sorts the values of a collection in ascending order by default.
Keyword ascending is optional here. Use descending keyword to sort collection in
descending order.

Example: OrderBy in Query Syntax C#

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 ascend
ing order
select s;

var orderByDescendingResult = from s in studentList //Sorts the studentList collectio


n in descending order
orderby s.StudentName descending
select s;

Example: OrderBy in Query Syntax VB.Net

30 | P a g e
Dim orderByResult = From s In studentList
Order By s.StudentName
Select s

Dim orderByDescendingResult = From s In studentList


Order By s.StudentName Descending
Select s

orderByResult in the above example would contain following elements after


execution:

Bill

John

Ram

Ron

Steve

orderByDescendingResult in the above example would contain following elements


after execution:

Steve

Ron

Ram

John

Bill

31 | P a g e
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 Extension method overloads in C#:

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


urce> source, Func<TSource, TKey> keySelector);

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


urce> 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#

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

Example: OrderBy in Method Syntax VB.Net

Dim sortedResult = studentList.OrderBy(Function(s) s.StudentName)

Note :Method syntax does not allow the decending keyword to sorts the
collection in decending order. Use OrderByDecending() method for it.

OrderByDescending:
OrderByDescending sorts the collection in descending order.

OrderByDescending is valid only with the Method syntax. It is not valid in query
syntax because the query syntax uses ascending and descending attributes as
shown above.

Example: OrderByDescending C#

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


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

32 | P a g e
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 result = studentList.OrderByDescending(s => s.StudentName);

Example: OrderByDescending VB.Net

Dim result = studentList.OrderByDescending(Function(s) s.StudentName)

A result in the above example would contain following elements after execution.

Steve

Ron

Ram

John

Bill

Please note that OrderByDescending is not supported in query syntax. Use the
decending keyword instead.

Sorting on multiple fields:


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#

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 },
new Student() { StudentID = 6, StudentName = "Ram" , Age = 18 }

33 | P a g e
};

var orderByResult = from s in studentList


orderby s.StudentName, s.Age
select new { s.StudentName, s.Age };

In the above example, studentList collection includes two identical


StudentNames, Ram. So now, studentList would be first sorted based on
StudentName and then by Age in ascending order. So, orderByResult would
contain following elements after execution

StudentName: Bill, Age: 25

StudentName: John, Age: 18

StudentName: Ram, Age: 18

StudentName: Ram, Age: 20

StudentName: Ron, Age: 19

StudentName: Steve, Age: 15

Note :Multiple sorting in method syntax works differently. Use ThenBy or


ThenByDecending extension methods for secondary sorting.

Points to Remember:
1. LINQ includes five sorting operators: OrderBy, OrderByDescending,
ThenBy, ThenByDescending and Reverse
2. LINQ query syntax does not support OrderByDescending, ThenBy,
ThenByDescending and Reverse. It only supports 'Order By' clause with
'ascending' and 'descending' sorting direction.
3. LINQ query syntax supports multiple sorting fields seperated by comma
whereas you have to use ThenBy & ThenByDescending methods for
secondary sorting.

34 | P a g e
Sorting Operators: ThenBy &
ThenByDescending
We have seen how to do sorting using multiple fields in query syntax in the
previous section.

Multiple sorting in method syntax is supported by using ThenBy and


ThenByDescending extension methods.

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:

Example: ThenBy & ThenByDescending

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 },
new Student() { StudentID = 6, StudentName = "Ram" , Age = 18 }
};
var thenByResult = studentList.OrderBy(s => s.StudentName).ThenBy(s => s.Age);

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


s.Age);

35 | P a g e
As you can see in the above example, we first sort a studentList collection by
StudentName and then by Age. So now, thenByResult would contain follwoing
elements after sorting:

StudentName: Bill, Age: 25

StudentName: John, Age: 18

StudentName: Ram, Age: 18

StudentName: Ram, Age: 20

StudentName: Ron, Age: 19

StudentName: Steve, Age: 15

thenByDescResult would contain following elements. Please notice that Ram with
age 20 comes before Ram with age 18 because it has used ThenByDescending.

StudentName: Bill, Age: 25

StudentName: John, Age: 18

StudentName: Ram, Age: 20

StudentName: Ram, Age: 18

StudentName: Ron, Age: 19

StudentName: Steve, Age: 15

You can use ThenBy and ThenByDescending method same way in VB.Net as
below:

36 | P a g e
Example: ThenBy & ThenByDescending VB.Net

Dim sortedResult = studentList.OrderBy(Function(s) s.StudentName).ThenBy(Function(s)


s.StudentName)

Dim sortedResult = studentList.OrderBy(Function(s) s.StudentName).ThenByDescending(Fu


nction(s) s.StudentName)

Points to Remember :
1. OrderBy and ThenBy sorts collections in ascending order by default.
2. ThenBy or ThenByDescending is used for second level sorting in method
syntax.
3. ThenByDescending method sorts the collection in decending order on
another field.
4. ThenBy or ThenByDescending is NOT applicable in Query syntax.
5. Apply secondary sorting in query syntax by separating fields using comma.

Grouping Operator: 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 specifies
the grouping key value.

Grouping
Operators Description

GroupBy The GroupBy operator returns groups of elements based on some key value. Each group is represente
IGrouping<TKey, TElement> object.

37 | P a g e
Grouping
Operators Description

ToLookup ToLookup is the same as GroupBy; the only difference is the execution of GroupBy is deferred wherea
ToLookup execution is immediate.

GroupBy:

A LINQ query can end with a GroupBy or Select clause.

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.

The result of GroupBy operators is a collection of groups. For example, GroupBy


returns IEnumerable<IGrouping<TKey,Student>> from the Student collection:

Return 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.

Example: GroupBy in Query syntax C#

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 = "Abram" , Age = 21 }
};

38 | P a g e
var groupedResult = from s in studentList
group s by s.Age;

//iterate each group


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

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


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

Output:

AgeGroup: 18

StudentName: John

StudentName: Bill

AgeGroup: 21

StudentName: Steve

StudentName: Abram

AgeGroup: 20

StudentName: Ram

As you can see in the above example, you can iterate the group using a 'foreach'
loop, where each group contains a key and inner collection. The following figure
shows the result in debug view.

39 | P a g e
Grouped collection with key and inner collection

Use "Into Group" with the 'Group By' clause in VB.Net as shown below.

Example: GroupBy clause in VB.Net

Dim groupQuery = From s In studentList


Group By s.Age Into Group

For Each group In groupQuery


Console.WriteLine("Age Group: {0}", group.Age) // Each group has key property nam
e

For Each student In group.Group // Each group has inner collection


Console.WriteLine("Student Name: {0}", student.StudentName)
Next

Next

Notice that each group will have a property name on which group is performed.
In the above example, we have used Age to form a group so each group will have
"Age" property name instead of "Key" as a property name.

Output:

AgeGroup: 18

StudentName: John

StudentName: Bill

AgeGroup: 21

StudentName: Steve

40 | P a g e
StudentName: Abram

AgeGroup: 20

StudentName: Ram

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#

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 = "Abram" , Age = 21 }
};

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

foreach (var group in groupedResult)


{
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);
}

Example: GroupBy in method syntax VB.Net

Dim groupQuery = studentList.GroupBy(Function(s) s.Age)

For Each group In groupQuery

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

For Each student In group.AsEnumerable() //Each group has a inner collection


Console.WriteLine("Student Name: {0}", student.StudentName)
Next

Next

41 | P a g e
Output:

AgeGroup: 18

StudentName: John

StudentName: Bill

AgeGroup: 21

StudentName: Steve

StudentName: Abram

AgeGroup: 20

StudentName: 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#

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 = "Abram" , 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 ke
y

42 | P a g e
foreach(Student s in group) //Each group has a inner collection
Console.WriteLine("Student Name: {0}", s.StudentName);
}

Example: ToLookup in method syntax VB.Net

Dim loopupResult = studentList.ToLookup(Function(s) s.Age)

Points to Remember :
1. GroupBy & ToLookup return a collection that has a key and an inner
collection based on a key field value.
2. The execution of GroupBy is deferred whereas that of ToLookup is
immediate.
3. A LINQ query syntax can be end with the GroupBy or Select clause.

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
Outer Join of SQL.

43 | P a g e
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 overload methods as shown below.

C#:

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


le<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Fun
c<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector);

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


le<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Fun
c<TInner, TKey> innerKeySelector, Func<TOuter, TInner, TResult> resultSelector, IEqua
lityComparer<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.

Consider the following example.

Example: Join operator C#

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


new Student() { StudentID = 1, StudentName = "John", Age = 13, StandardID =1 },
new Student() { StudentID = 2, StudentName = "Moin", 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 = 15 }
};

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
{

44 | P a g e
StudentName = student.StudentName,
StandardName = standard.StandardName
});

The following image illustrate the parts of Join operator in the above example.

join operator

In the above example of join query, studentList is outer sequence because query
starts from it. First parameter in Join method is used to specify the inner sequence
which is standardList in the above example. Second and third parameter of Join
method is used to specify a field whose value should be match using lambda
expression in order to include element in the result. The key selector for the outer
sequence student => student.StandardID indicates that take StandardID field of each
elements of studentList should be match with the key of inner sequence standard
=> standard.StandardID. If value of both the key field is matched then include that
element into result.

The last parameter in Join method is an expression to formulate the result. In the
above example, result selector includes StudentName and StandardName
property of both the sequence.

StandardID Key of both the sequences (collections) must match otherwise the
item will not be included in the result. For example, Ron is not associated with
any standard so Ron is not included in the result collection. innerJoinResult in the
above example would contain following elements after execution:

John - Standard 1

Moin - Standard 1

Bill - Standard 2

45 | P a g e
Ram - Standard 2

The following example demonstrates the Join operator in method syntax in


VB.Net.

Example: Join operator VB.Net

Dim joinResult = studentList.Join(standardList,


Function(s) s.StandardID,
Function(std) std.StandardID,
Function(s, std) New With
{
.StudentName = s.StudentName,
.StandardName = std.StandardName
});

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#

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


new Student() { StudentID = 1, StudentName = "John", Age = 13, StandardID =1 },
new Student() { StudentID = 2, StudentName = "Moin", Age = 21, StandardID =1 },
new Student() { StudentID = 3, StudentName = "Bill", Age = 18, StandardID =2 },
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20, StandardID =2 },

46 | P a g e
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};

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 = 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
};

Example: Join operator in query syntax VB.Net

Dim innerJoinResult = From s In studentList ' outer sequence


Join std In standardList ' inner sequence
On s.StandardID Equals std.StandardID ' key selector
Select _ ' result selector
StudentName = s.StudentName,
StandardName = std.StandardName

Output:

John - Standard 1

Moin - Standard 1

Bill - Standard 2

Ram - Standard 2

Note :Use the equals operator to match key selector in query syntax. == is not
valid.

47 | P a g e
Points to Remember :
1. Join and GroupJoin are joining operators.
2. Join is like inner join of SQL. It returns a new collection that contains
common elements from two collections whosh keys matches.
3. Join operates on two sequences inner sequence and outer sequence and
produces a result sequence.
4. Join query syntax:
from... in outerSequence
join... in innerSequence
on outerKey equals innerKey
select ...

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 it returns a group result.
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 in Method Syntax:


GroupJoin requires same parameters as Join. GroupJoin has following two
overload methods:

GroupJoin method overloads C#

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


merable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector
, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> res
ultSelector);

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


merable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector
, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> res
ultSelector, 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.

48 | P a g e
Consider the following example.

Example: GroupJoin in Method syntax C#

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


new Student() { StudentID = 1, StudentName = "John", Age = 13, StandardID =1 },
new Student() { StudentID = 2, StudentName = "Moin", 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 = 15 }
};

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 groupJoinResult = 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 groupJoinResult)


{
Console.WriteLine(item.StandarFulldName );

foreach(var stud in item.Students)


Console.WriteLine(stud.StudentName);
}

Output:

Standard 1:

John,

Moin,

Standard 2:

Bill,

49 | P a g e
Ram,

Standard 3:

In the above example of GroupJoin query, standardList is the outer sequence,


because the query starts from it. The first parameter in GroupJoin method is to
specify the inner sequence, which is studentList in the above example. The second
and third parameters of the GroupJoin() method are to specify a field whose value
should be matched using lambda expression, in order to include element in the
result. The key selector for the outer sequence standard =>
standard.StandardID indicates that StandardID field of each elements in
standardList should be match with the key of inner sequence studentList student
=> student.StandardID. If value of both the key field is matched then include that
element into grouped collection studentsGroup where key would be StandardID.

The last parameter in Join method is an expression to formulate the result. In the
above example, result selector includes grouped collection studentGr oup and
StandardName.

The following image illustrate that inner sequence grouped into studentsGroup
collection for matching StandardID key and that grouped collection can be used
to formulate the result.

Grouping Operator - GroupJoin

Resultset would include an anonymous objects that has the Students and
StandardFullName properties. Students property will be a collection of Students
whose StandardID matches with Standard.StandardID.

50 | P a g e
GroupJoin Result in Debug View

You can access the result using a 'foreach' loop. Each element will have the
StandardFullName & Students property, where Students will be a collection.

Example: Access GroupJoin Result in C#

foreach (var item in groupJoinResult)


{
Console.WriteLine(item.StandarFulldName );

foreach(var stud in item.Students)


Console.WriteLine(stud.StudentName);
}

Following is an example of GroupJoin in VB.Net:

Example: GroupJoin in Method syntax VB.Net

Dim groupJoin = standardList.GroupJoin( ' outer sequence


studentList, ' inner sequence
Function(s) s.StandardID, ' outerKeySelector
Function(stud) stud.StandardID, ' innerKeySelector
Function(s, studentGroup) New With { ' result selector
.students = studentGroup,
.standardName = s.StandardName
})

For Each item In groupJoin

Console.WriteLine(item.standardName)

For Each std In item.students


Console.WriteLine( std.StudentName)

51 | P a g e
Next

Next

Output:

Standard 1:

John,

Moin,

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.

52 | P a g e
Example: GroupJoin Query Syntax C#

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


new Student() { StudentID = 1, StudentName = "John", Age = 13, StandardID =1 },
new Student() { StudentID = 2, StudentName = "Moin", 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 = 15 }
};

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 groupJoinResult = 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 groupJoinResult)


{
Console.WriteLine(item.StandarFulldName );

foreach(var stud in item.Students)


Console.WriteLine(stud.StudentName);
}

Example: GroupJoin Query Syntax VB.Net

Dim groupJoin = From s In standardList


Group Join stud In studentList
On stud.StandardID Equals s.StandardID
Into Group _
Select _
StudentsGroup = Group,
StandardName = s.StandardName

Output:

Standard 1:

John,

53 | P a g e
Moin,

Standard 2:

Bill,

Ram,

Standard 3:

In the VB.Net, the InTo keyword will create a group of all students of same
standard and assign it to the Group keyword. So, use Group in the projection
result.

Note :Use of the equals operator to match key selector. == is not valid.

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.

Select in Query Syntax:


LINQ query syntax must end with a Select or GroupBy clause. The following
example of the select clause returns a collection of range variable s (student
object) from studentList collection without any changes:

Example: Select in query syntax C#

54 | P a g e
var selectResult = from s in studentList
select s; // returns a collection of student object

The select operator can be used to formulat the result as per our requirement. It
can be used to return a collection of custom class or anonymous type which
includes properties as per our need.

The following example of the select clause returns a collection of anonymous


type containing the Name and Age property.

Example: Select operator in query syntax C#

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 = from s in studentList
select new { Name = "Mr. " + s.StudentName, Age = s.age };

// iterate selectResult
foreach (var item in selectResult)
Console.WriteLine("Student Name: {0}, Age: {1}", item.Name, item.Age);

Example: Select operator in query syntax VB.Net

Dim selectResult = From s In studentList


Select New With {.Name = s.StudentName, .Age = s.Age}

Output:

Student Name: Mr. John, Age: 13

Student Name: Mr. Moin, Age: 21

Student Name: Mr. Bill, Age: 18

Student Name: Mr. Ram, Age: 20

Student Name: Mr. Ron, Age: 15

55 | P a g e
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#

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


new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
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 = 21 }
};

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


Age = s.age });

In the above example, selectResult would contain anonymous objects with Name
and Age property as shown below in the debug view.

Select
clause returns an Anonymous objects

Example: Select in method syntax VB.Net

Dim selectResult = studentList.Select(Function(s) New With {.Name = s.StudentName,


.Age = s.Age})

Select Many:
The SelectMany operator projects sequences of values that are based on a
transform function and then flattens them into one sequence.

Visit MSDN for more information on projection operators.

56 | P a g e
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

Contain 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#

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 }
};

// checks whether all the students are teenagers


bool isAllStudentTeenAger = studentList.All(s => s.age > 12 && s.age < 20);

Example: All operator VB.Net

Dim isAllStudentTeenAger = studentList.All(Function(s) s.Age > 12 And s.Age < 20)

Output:

57 | P a g e
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#

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

Example: Any operator VB.Net

Dim isAnyStudentTeenAger = studentList.Any(Function(s) s.Age > 12 And s.Age < 20)

Output:

true

Note :Quantifier operators are Not Supported with C# query syntax.

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.

Contains overload methods C#

public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value)


;

58 | P a g e
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value,
IEqualityComparer<TSource> comparer);

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#

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


bool result = intList.Contains(10); // returns false

Example: Contains operator VB.Net

Dim intList As IList(Of Integer) = New List(Of Integer) From {1, 2, 3, 4, 5}


Dim result = intList.Contains(10) ' returns false

The above example works well with primitive data types. However, it will not work
with a custom class. Consider the following example:

C#:

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 }
};

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


bool result = studentList.Contains(std); //returns false

As you can see in the above example, Contains returns false even if "Bill" exists
in the studentList. This is because the Contains extension method only compares
reference of an object but not the actual values of an object. So to compare values
of the student object, you need to create a class by implementing
IEqualityComparer interface, that compares values of two Student objects and
returns boolean.

The following is a StudentComparer class that implements


IEqualityComparer<Student> interface to compare values of two Students
objects:

Example: IEqualityComperer

59 | P a g e
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.GetHashCode();
}
}

Now, you can use the above StudentComparer class in second overload method
of Contains extension method that accepts second parameter of
IEqualityComparer type, as below:

Example: Contains with Comparer class C#

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 }
};

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


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

So thus, you have to use comparer class in order to get corrent result from
Contains extension method for custom classes.

The following is a similar example in VB.Net:

Example: Contains with Comparer class VB.Net

public class Student


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

Public Class StudentComparer


Implements IEqualityComparer(Of Student)

60 | P a g e
Public Function Equals1(x As Student, y As Student) As Boolean Implements IEquali
tyComparer(Of Student).Equals
If (x.StudentID = y.StudentID And x.StudentName.ToLower() = y.StudentName.ToL
ower()) Then
Return True

Return False
End If
End Function

Public Function GetHashCode1(obj As Student) As Integer Implements IEqualityCompa


rer(Of Student).GetHashCode
Return obj.GetHashCode()
End Function
End Class

Sub Main
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 18},
New Student() With {.StudentID = 2, .StudentName = "Steve", .Age = 15},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 25},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 19}
}

Dim std As New Student With {.StudentID = 3, .StudentName = "Bill"}


Dim result = studentList.Contains(std, New StudentComparer()) ' returns true

Note :Quantifier operators are Not Supported with query syntax in C# or


VB.Net.

Points to Remember:
1. All, Any & Contains are quantifier operators in LINQ.
2. All checks if all the elements in a sequence satisfies the specified condition.
3. Any check if any of the elements in a sequence satisfies the specified
condition
4. Contains operator checks whether specified element exists in the collection
or not.
5. Use custom class that derives IEqualityOperator with Contains to check for
the object in the collection.
6. All, Any & Contains are not supported in query syntax in C# or VB.Net.

61 | P a g e
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 method overloads C#

public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSour


ce, TSource, TSource> func);

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


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

62 | P a g e
public static TResult Aggregate<TSource, TAccumulate, TResult>(this IEnumerable<TSour
ce> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func, Func<TAcc
umulate, TResult> resultSelector);

Consider the following example of Aggregate method.

Example: Aggregate operator in method syntax C#

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

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


Console.log(commaSeperatedString);
Output:

One, Two, Three, Four, Five

In the above example, Aggregate extension method returns comma separated


strings from strList collection. The following image illustrates the whole aggregate
operation performed in the above example.

Aggregate extension method

As per the above figure, first item of strList "One" will be pass as s1 and rest of
the items will be passed as s2. The lambda expression (s1, s2) => s1 + ", " +
s2 will be treated like s1 = s1 + ", " + s1 where s1 will be accumulated for each
item in the collection. Thus, Aggregate method will return comma separated
string.

Example: Aggregate operator in method syntax VB.Net

63 | P a g e
Dim strList As IList(Of String) = New List(Of String) From {
"One",
"Two",
"Three",
"Four",
"Five"
}

Dim commaSeparatedString = strList.Aggregate(Function(s1, s2) s1 + ", " + s2)

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 method with seed value in C#

// 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 }
};

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


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

Example: Aggregate method with seed value in VB.Net

// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}
Dim commaSeparatedStudentNames = studentList.Aggregate(Of String)(
"Student Names: ",

64 | P a g e
Function(str, s) str + s.StudentName + ",")

Console.log(commaSeparatedStudentNames);

Output:

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

In the above example, the first parameter of the Aggregate method is the
"Student Names: " string that will be accumulated with all student names. The
comma in the lambda expression will be passed as a second parameter.

The following example use Aggregate operator to add the age of all the students.

Example: Aggregate method with seed value in C#

// 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 }
};

string totalAge = studentList.Aggregate<Student, int>(0, (totalAge, s) => totalAge +=


s.Age ); // returns 87

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.

Consider the following example.

Example: Aggregate method C#

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 }
};

65 | P a g e
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 ));
// result selector that removes last comma

In the above example, we have specified a lambda expression str =>


str.Substring(0,str.Length - 1 ) which will remove the last comma in the string
result. Below is the same example in VB.Net.

Example: Aggregate method VB.Net

// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim commaSeparatedStudentNames = studentList.Aggregate(Of String, String)(


String.Empty,
Function(str, s) str + s.StudentName + ",",
Function(str) str.Substring(0, str.Length - 1))

Console.log(commaSeparatedStudentNames);

Output:

John, Moin, Bill, Ram, Ron

Note :Aggregate operator is Not Supported with query syntax in C# or


VB.Net.

Learn about another aggregate operator - Average in the next section.

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.

66 | P a g e
Example: Average operator in method syntax C#
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);

Example: Average operator in method syntax VB.Net


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim avgAge = studentList.Average(Function(s) s.Age)

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

Output:

Average Age of Student: 17.4

The Average operator in query syntax is Not Supported in C#. However, it is


supported in VB.Net as shown below.

Example: Average operator in query syntax VB.Net


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim avgAge = Aggregate st In studentList Into Average(st.Age)

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

Output:

67 | P a g e
Average Age of Student: 17.4

Learn about another aggregate operator - Count in the next section.

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() method overloads in C#

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 returns the number of elements in a collection using the
Count() method in the method syntax.

Example: Count() in C#

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 = "Mathew" , Age = 15 }
};

var numOfStudents = studentList.Count();

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

Example: Count() in VB.Net

Dim studentList = New List(Of Student) From {


New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},

68 | P a g e
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim numOfStudents = studentList.Count()

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

Output:

Number of Students: 5

In the following example, we get the count of students whose age is 18 or more
by specifying condition in the Count method:

C#:

// 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 = "Mathew" , Age = 15 }
};

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

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

Output:

Number of Students: 3

Note :Count() extension method with predicate parameter is Not Supported in


VB.Net.

Count operator in query syntax:


Example: Count operator in query syntax VB.Net

// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},

69 | P a g e
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim numOfStudents = Aggregate st In studentList


Into Count(st.Age >= 18)

Console.WriteLine("Number of Student: {0}", numOfStudents);

Output:

Number of Students: 3

C# Query Syntax doesn't support aggregation operators. However, you can wrap
the query into brackets and use an aggregation functions as shown below.

Example: Count operator in query syntax C#

var totalAge = (from s in studentList


select s.age).Count();

Learn about another aggregate operator - Max in the next section.

Aggregation Operator: Max


The Max operator returns the largest numeric element from a collection.

In the following example, Max returns maximum age from the studentList
collection:

Example: Max operator in method syntax C#

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 maxAge = studentList.Max(s => s.Age);

Console.WriteLine("Maximum Age of Student: {0}", maxAge);

Example: Max operator in method syntax VB.Net

70 | P a g e
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim maxAge = studentList.Max(Function(s) s.Age)

Console.WriteLine("Maximum Age of Student: {0}", maxAge);

Output:

Maximum Age of Student: 21

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:

C#:

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;
}

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 = "Mathew" , Age = 15 }
};

var studentWithLongName = studentList.Max();

71 | P a g e
Console.WriteLine("Student ID: {0}, Student Name: {1}", studentWithLongName.S
tudentID, studentWithLongName.StudentName);
}
}
Output:

Student ID: 5, Student Name: Mathew

Note :You can use Min extension method/operator the same way as Max.

As per the above example, to find the student with the longest name, you need
to implement IComparable<T> interface and compare student names' length in
CompareTo method. So now, you can use Max() method which will use
CompareTo method in order to return appropriate result.

Max operator in Query Syntax:


Max operator is Not Supported in C# Query syntax. However, it is supported in
VB.Net query syntax as shown below.

Example: Max operator in query syntax VB.Net

Dim studentList = New List(Of Student) From {


New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim maxAge = Aggregate st In studentList Into Max(st.Age)

Console.WriteLine("Maximum Age of Student: {0}", maxAge.FirstOrDefault.Max);

Output:

Maximum Age of Student: 21

Learn about another aggregate operator - Sum in the next section.

72 | P a g e
Aggregation Operator: Sum
The Sum() method calculates the sum of numeric items in the collection.

The following example returns the total age of all the students in a collection.

Example: Sum in method syntax C#

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 totalAge = studentList.Sum(s => s.Age);

Console.WriteLine("Total Age of Student: {0}", totalAge);

Example: Sum in method syntax

// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim totalAge = studentList.Sum(Function(s) s.Age)

Console.WriteLine("Total Age of Student: {0}", totalAge);

Output:

Total Age of Student: 87

Sum operator in query syntax:


Sum operator is Not Supported in C# Query syntax.

Example: Sum operator in query syntax VB.Net

73 | P a g e
// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim totalAge = Aggregate st In studentList Into Sum(st.Age)

Console.WriteLine("Total Age of Student: {0}", totalAge);

Output:

87

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

The following table lists all the Element methods of 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 ind
out of range.

First Returns the first element of a collection, or the first element that satisfies a condit

FirstOrDefault Returns the first element of a collection, or the first element that satisfies a condit
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 conditio

74 | P a g e
Element Operators (Methods) Description

LastOrDefault Returns the last element of a collection, or the last element that satisfies a conditio
Returns a default value if no such element exists.

Single Returns the only element of a collection, or the only element that satisfies a condit

SingleOrDefault Returns the only element of a collection, or the only element that satisfies a condit
Returns a default value if no such element exists or the collection does not contain
exactly one element.

The following image illustrates the return value from each element methods:

Element
Operators

ElementAt:
ElementAt extension method returns an element at the specified index from a
collection. Please note that index is a zero based index.

Example: ElementAt in method syntax C#

// 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 } ,
};

75 | P a g e
//returns third student Bill (zero based index)
var student1 = studentList.ElementAt(2);

//returns fifth student Ron (zero based index)


var student2 = studentList.ElementAt(4);

//throws ArgumentOutOfRangeException
var student3 = studentList.ElementAt(6);

Example: ElementAt in method syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

' returns third student - Bill (zero based index)


Dim student1 = studentList.ElementAt(2)

' returns fifth student - Ron (zero based index)


Dim student2 = studentList.ElementAt(4)

' throws ArgumentOutOfRangeException


Dim student3 = studentList.ElementAt(6)

In the above example, studentList.ElementAt(2) returns 3rd element from


studentList collection because 2nd index means 3rd element as index starts from
zero. Also, studentList.ElementAt(6)throws an ArgumentOutOfRangeException
because studentList collection has only 5 elements. So accessing 6th element will
throw an exception.

ElementAtOrDefault:
ElementAtOrDefault extension method overcomes limitation of ElementAt
method. It returns default value for underlying type of generic collection if the
specified index is out of range. Consider the following example.

Example: ElementAtOrDefault in method syntax C#

// 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 }

76 | P a g e
};

//returns third element-Bill from 3rd place(zero based index)


var student1 = studentList.ElementAtOrDefault(2);

//returns null because null is default value for object


var student2 = studentList.ElementAtOrDefault(6);

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

//returns 0 because 0 is default value for int


var intVal = intList.ElementAtOrDefault(6);

Example: ElementAtOrDefault in method syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

' returns third element object-Bill from 3rd place(zero based index)
Dim student1 = studentList.ElementAtOrDefault(2)

' returns null because null is default value for object


Dim student2 = studentList.ElementAtOrDefault(6)

Dim intList = New List(Of int) From { 1, 2, 3, 4, 5 }

//returns 0 because 0 is default value for int


Dim intVal = intList.ElementAtOrDefault(6);

In the above example, ElementAtOrDefault(6) returns null and doesn't throw an


exception, even if index is out of range. In the same way, ElementAtOrDefault
method returns 0 from int type collection if index is out of range because 0 is a
default value of int.

Thus, it is advisable to use the ElementAtOrDefault extension method to eliminate


the possibility of a runtime exception.

Learn about another element operator First and FirstOrDefault in the next section.

77 | P a g e
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 defa
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.

Overload methods of First and FirstOrDefault - C#

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);

First:
First() method returns the element at the zeroth index (first element) from a
collection, or the first element that satisfies a condition starting from the zero
index.

Example: First() in C#:

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

78 | P a g e
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
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 firstStudent = studentList.First();


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

var firstTeenAgerStudent = studentList.First(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("First TeenAger Student Name : {0}", firstTeenAgerStudent.StudentNa
me);

// following throws InvalidOperationException: Sequence contains no matching element


// var student = studentList.First(s => s.Age > 30);

Example: First() in VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim firstStudent = studentList.First();


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

Dim firstTeenAgerStudent = studentList.First(function(s) s => s.Age > 12 && s.Age < 2


0 );
Console.WriteLine("First TeenAger Student Name : {0}", firstTeenAgerStudent.StudentNa
me);

' following throws InvalidOperationException: Sequence contains no matching element


' Dim student = studentList.First(function(s) s.Age > 30);

Output:

First Student Name : John

First TeenAger Student Name :Bill

In the above example, studentList.First(s => s.Age > 30); will throw
InvalidOperationException because studentList collection doesn't contain any
student object with Age > 30.

79 | P a g e
Note :Using First() method with empty collection will throw
InvalidOperationException.

FirstOrDefault:
FirstOrDefault is same as First extension method except that it returns the default
value of the underlying type of generic collection, instead of throwing an
InvalidOperationException for empty collection or no element satisfies the
specified condition.

Example: FirstOrDefault in method syntax C#

// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
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 firstStudent = studentList.FirstOrDefault();


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

var firstTeenAgerStudent = studentList.FirstOrDefault(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("First TeenAger Student Name : {0}", firstTeenAgerStudent.StudentNa
me);

var student = studentList.FirstOrDefault(s => s.age > 30);


Console.WriteLine("Student with more than 30 yrs age: {0}", student);

Example: FirstOrDefault in method syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim firstStudent = studentList.FirstOrDefault();


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

Dim firstTeenAgerStudent = studentList.studentList.FirstOrDefault(function(s) s => s.


Age > 12 && s.Age < 20 );
Console.WriteLine("First TeenAger Student Name : {0}", firstTeenAgerStudent.StudentNa
me);

80 | P a g e
Dim student = studentList.studentList.FirstOrDefault(function(s) s.Age > 30);
Console.WriteLine("More than 30 yrs old: {0}", student);

Output:

First Student Name : John

First TeenAger Student Name :Bill

More than 30 yrs old:

Always check return element for null value before using it to avoid null reference
exception.

In the above example, studentList.FirstOrDefault(s => s.age > 30) returns null
instead of throwing an exception. So the output doesn't display anything for 'null'.

FirstOrDefault can be used in the query syntax same way as First on resulted
query.

First & FirstOrDefault in Query Syntax:


Query syntax in C# and VB.Net doesn't support First or FirstOrDefault operators.
However, you can use First or FirstOrDefault method on the IEnumerable variable
or by wrapping whole query inside brackets as shown below.

Example: First & FirstOrDefault in query syntax C#

// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
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 query = from s in studentList
select s;

Student fistStudent = query.First();


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

Student firstTeenStudent = query.FirstOrDefault(s => s.Age > 12 && s.Age < 20);

81 | P a g e
Console.WriteLine("First TeenAger Student Name : {0}", firstTeenAgerStudent.StudentNa
me);

// returns John
var var = (from s in studentList
select s).First();

Example: First & FirstOrDefault in query syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim query = from s in studentList


select s;

Dim fistStudent = query.First();


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

Dim firstTeenAgerStudent = query.First(function(s) s => s.Age > 12 && s.Age < 20 );


Console.WriteLine("First TeenAger Student Name : {0}", firstTeenAgerStudent.StudentNa
me);

' returns John


Dim var = (from s in studentList
select s).First();
Output:

First Student Name : John

First TeenAger Student Name :Bill

Element Operators : Last & LastOrDefault

82 | P a g e
Element
Operators Description

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 defau
value if no such element exists.

Last and LastOrDefault has two overload methods. One overload method doesn't
take any input parameter and returns last element from the collection. Second
overload method takes a lambda expression to specify a condition and returns
first element that satisfies the specified condition.

Overload methods of Last and LastOrDefault method - C#:

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

public static TSource Last<TSource>(this IEnumerable<TSource> source, Func<TSource, b


ool> predicate);

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

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


Source, bool> predicate);

Last:
The Last() method returns the last element of a collection, or the last element
that satisfies the specified condition.

Example: Last() in method syntax C#

// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
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 lastStudent = studentList.Last();


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

var lastTeenAgerStudent = studentList.Last(s => s.Age > 12 && s.Age < 20);

83 | P a g e
Console.WriteLine("Last TeenAger Student Name : {0}", lastTeenAgerStudent.StudentName
);

// following throws InvalidOperationException: Sequence contains no matching element


// var student = studentList.Last(s => s.age > 30);

Example: Last() in method syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim lastStudent = studentList.Last();


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

Dim lastTeenAgerStudent = studentList.First(function(s) s => s.Age > 12 && s.Age < 20


);
Console.WriteLine("Last TeenAger Student Name : {0}", lastTeenAgerStudent.StudentName
);

' following throws InvalidOperationException: Sequence contains no matching element


' Dim student = studentList.Last(function(s) s.Age > 30);

Output:

Last Student Name : Ron

Last TeenAger Student Name :Ron

In the above example, studentList.Last(s => s.Age > 30); will throw
InvalidOperationException because studentList collection doesn't contain any
student object with Age > 30. In the same way, Last() method throws
InvalidOperationException on empty collection.

LastOrDefault:
LastOrDefault is same as the Last extension method, except that it returns default
value of underlying type of generic collection instead of throwing an
InvalidOperationException if no element satisfies the specified condition or the
collection is empty.

Example: LastOrDefault in method syntax C#

84 | P a g e
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
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 lastStudent = studentList.LastOrDefault();


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

var lastTeenAgerStudent = studentList.LastOrDefault(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("Last TeenAger Student Name : {0}", lastTeenAgerStudent.StudentName
);

var student = studentList.LastOrDefault(s => s.age > 30);


Console.WriteLine("Last Student with more than 30 yrs age: {0}", student);

Example: LastOrDefault in method syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim lastStudent = studentList.LastOrDefault();


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

Dim lastTeenAgerStudent = studentList.studentList.LastOrDefault(function(s) s => s.Ag


e > 12 && s.Age < 20 );
Console.WriteLine("Last TeenAger Student Name : {0}", lastTeenAgerStudent.StudentName
);

Dim student = studentList.studentList.LastOrDefault(function(s) s.Age > 30);


Console.WriteLine("Last Student with more than 30 yrs age: {0}", student);

Output:

Last Student Name : Ron

Last TeenAger Student Name :Ron

Last Student with more than 30 yrs age:

85 | P a g e
In the above example, studentList.LastOrDefault(s => s.age > 30) returns null
(Objects' default value is null) instead of throwing an exception. So output doesn't
display anything for 'null'.

Last & LastOrDefault in Query Syntax:


Query syntax in C# and VB.Net doesn't support Last or LastOrDefault operators.
However, you can use Last or LastOrDefault method on the resulted query
variable:

Example: Last\LastOrDefault in query syntax C#:

// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
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 query = from s in studentList
select s;

Student lastStudent = query.Last();


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

Student lastTeenStudent = query.LastOrDefault(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("First TeenAger Student Name : {0}", lastTeenAgerStudent.StudentNam
e);

var lastStudent2 = (from s in studentList


select s).Last();

Example: Last\LastOrDefault in query syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim query = from s in studentList


select s;

Dim lastStudent = query.Last();


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

86 | P a g e
Dim lastTeenAgerStudent = query.LastOrDefault(function(s) s => s.Age > 12 && s.Age <
20 );
Console.WriteLine("Last TeenAger Student Name : {0}", lastTeenAgerStudent.StudentName
);

Dim lastStudent2 = (from s in studentList


select s).Last();

Output:

Last Student Name : Ron

Last TeenAger Student Name :Ron

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() fo
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 throwin
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 collecti

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.

Overloads of Single and SingleOrDefault extension method- C#:

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

87 | P a g e
public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource,
bool> predicate);

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

public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source, Func


<TSource, bool> predicate);

Single:
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.

Example: Single in method syntax C#

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

// throws InvalidOperationException as collection contains more than one element


var singleStudent = studentList.Single();

var singleTeenAgerStudent = studentList.Single(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("Single TeenAger Student Name : {0}", singleTeenAgerStudent.Student
Name);

IList<int> intList = new List<int>() { 1 };

var intVal = intList.Single();//returns 1


Console.WriteLine("Single integer: {0}", intVal);

Example: Single in method syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 28},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}

}
/ throws InvalidOperationException as collection contains more than one element

88 | P a g e
Dim singleStudent = studentList.Single();

Dim singleTeenAgerStudent = studentList.Single(function(s) s.Age > 12 && s.Age < 20);


Console.WriteLine("Single TeenAger Student Name : {0}", singleTeenAgerStudent.Student
Name);

Dim intList = new List(Of Student) From { 1 };

Dim intVal = intList.Single();


Console.WriteLine("Single integer: {0}", intVal);

Output:

Single TeenAger Student Name :Ron

Single integer: 1

The following example code throws an exception because Single found multiple
resulted elements:

C#:

// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
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 } ,
};

//throws InvalidOperationException because studentList contains multiple elements


var singleStudent = studentList.Single();

var singleTeenAgerStudent = studentList.Single(s => s.Age > 12 && s.Age < 20);//throw
s InvalidOperationException because studentList contains multiple teenager students

var Student = studentList.Single(s => s.Age > 30);//throws InvalidOperationException


because no student object satisfied the condition

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

var intVal = intList.Single();//throws InvalidOperationException because intList cont


ains multiple elements

89 | P a g e
SingleOrDefault:
The same as Single, except that it returns default value of a specified generic
type, instead of throwing an exception if no element found for the specified
condition. However, it will throw InvalidOperationException, if it found more than
one element for the specified condition in the collection.

Example: SingleOrDefault in method syntax C#

// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 24 }
new Student() { StudentID = 2, StudentName = "Moin", Age = 14 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 20 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 }
};

var singleTeenAgerStudent = studentList.SingleOrDefault(s => s.Age > 12 && s.Age < 20


);
Console.WriteLine("Single TeenAger Student Name : {0}", singleTeenAgerStudent.Student
Name);

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

var intVal = intList.SingleOrDefault(i => i > 4);


Console.WriteLine("Single integer greater than 4: {0}", intVal);

var intVal = intList.SingleOrDefault(i => i > 10);


Console.WriteLine("Single integer greater than 10: {0}", intVal);

VB.Net:

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 24},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 14},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 20},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
}

Dim singleTeenAgerStudent = studentList.SingleOrDefault(function(s) s.Age > 12 && s.A


ge < 20);
Console.WriteLine("Single TeenAger Student Name : {0}", singleTeenAgerStudent.Student
Name);

Dim intList = new List(Of Student) From { 1, 2, 3, 4, 5 };

Dim intVal = intList.Single(function(i) i > 4);


Console.WriteLine("Single integer greater than 4: {0}", intVal);

Dim intVal = intList.Single(function(i) i > 10);

90 | P a g e
Console.WriteLine("Single integer greater than 10: {0}", intVal);

Output:

Single TeenAger Student Name : Moin

Single integer greater than 4: 5

Single integer greater than 10: 0

Note :Single or SingleOrDefault expects only one element in the result. If it get
more than one elements in the result then it throws an exception.

Single/SingleOrDefault in Query Syntax:


Query syntax in C# and VB.Net doesn't support Single or SingleOrDefault
operators. However, you can use Single or SingleOrDefault method on the
resulted query variable or wrap the query into a bracket.

Example: Single or SingleOrDefault in query syntax C#:

// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 12 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 28 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 } ,
};
var query = from s in studentList
select s;

//throws InvalidOperationException because studentList contains multiple elements


Student Student = query.Single();

Student teenAgerStudent = query.SingleOrDefault(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("TeenAger Student Name : {0}", teenAgerStudent.StudentName);

Example: Single or SingleOrDefault in query syntax VB.Net

' Student collection


Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age = 12},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age = 21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 28},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},

91 | P a g e
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}

Dim query = from s in studentList


select s;

//throws InvalidOperationException because studentList contains multiple elements


Dim student = query.Single();

Dim teenAgerStudent = query.SingleOrDefault(function(s) s => s.Age > 12 && s.Age < 20


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

Output:

TeenAger Student Name :Ron

Equality Operator: SequenceEqual


There is only one equality operator: SequenceEqual. The SequenceEqual method
checks whether the number of elements and value of each element in two
collection 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#

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); // returns true


Console.WriteLine(isEqual);

Example: SequenceEqual in Method Syntax VB.Net

92 | P a g e
Dim strList1 = new List(Of String) From { "One", "Two", "Three", "Four", "Three" };
Dim strList2 = new List(Of String) From { "One", "Two", "Three", "Four", "Three" };

Dim isEqual = strList1.SequenceEqual(strList2); // returns true


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#

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

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


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

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


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

bool isStudentsEqual = stdList1.SequenceEqual(stdList2);// returns false

In the above example, studentList1 and studentList2 contains the same student
object, std. SostudentList1.SequenceEqual(studentList2) returns true. But, stdList1
and stdList2 contains two seperate student object, std1 and std2. So
now, stdList1.SequenceEqual(stdList2) will return false even if std1 and std2 contain
the same value.

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#:

class StudentComparer : IEqualityComparer<Student>


{
public bool Equals(Student x, Student y)
{

93 | P a g e
if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentNam
e.ToLower())
return true;

return false;
}

public int GetHashCode(Student obj)


{
return obj.GetHashCode();
}
}

Now, you can use above StudentComparer class in SequenceEqual extension


method as a second parameter to compare the values:

Example: Compare object type elements using SequenceEqual C#

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 = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};

IList<Student> studentList2 = 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 }
};

bool isStudentsEqual = studentList1.SequenceEqual(studentList2, new StudentComparer()


); // returns true

Points to Remember :
1. The SequenceEqual method compares the number of items and their
values for primitive data types.
2. The SequenceEqual method compares the reference of objects for
complex data types.

94 | P a g e
3. Concatenation Operator: Concat
4. The Concatenation operator Concate appends two sequences and returns a
new sequence (collection).
5. Example: Concate in C#
6.
7.
8. IList<string> collection1 = new List<string>() { "One", "Two", "Three" };
9. IList<string> collection2 = new List<string>() { "Five", "Six"};
10.
11. var concateResult = collection1.Concat(collection2);
12.
13. foreach (string str in concateResult)
14. Console.WriteLine(str);
15.
16. Example: Concate in VB.Net
17.
18. Dim concateResult = collection1.Concat(collection2);
19.
20. Output:

21. One

Two

22. ThreeConcate operator is not supported in query syntax in C# or VB.Net.

Five

Six

Generation Operators:
Generation operators create a new sequence (collection).

Method Description

DefaultIfEmpty Replaces an empty collection with a default valued collection

Empty Returns an empty collection

95 | P a g e
Method Description

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.

DefaultIfEmpty:
The DefaultIfEmpty extension method adds an element with a default value if the
sequence doesn't contains any element.

Example: DefaultIfEmpty C#

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


var newStudentList = studentList.DefaultIfEmpty();

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


Console.WriteLine("Element: {0} ",newStudentList.ElementAt(0) == null ? "null" : newS
tudentList.ElementAt(0).StudentName);

Output:

Count: 1

Element: null

Example: DefaultIfEmpty C#

IList<int> intList = new List<int>();


var newIntList = intList.DefaultIfEmpty();

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


Console.WriteLine("Element: {0} ",newIntList.ElementAt(0) == null ? "null" : newStude
ntList.ElementAt(0).StudentName);

Output:

96 | P a g e
Count: 1

Element: 0

You can also specify element to add if sequence is empty:

Example: DefaultIfEmpty C#:

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


var newStudentList = studentList.DefaultIfEmpty(new Student(){
StudentID = 1,
StudentName = "Bill" });

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


Console.WriteLine("Student Name: {0} ",newStudentList.ElementAt(0) == null ? "null" :
newStudentList.ElementAt(0).StudentName);

Output:

Count: 1

Element: Bill

Empty, Range and Repeat methods are not extension methods of


IEnumerable<T>. They are generic static methods of static Enumerable class.

Empty:
The Empty method generates an empty collection of IEnumerable<T> type.

Example: Enumerable.Empty()

var emptyStudentCollection = Enumerable.Empty<Student>();


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

var emptyIntCollection = Enumerable.Empty<Int32>();


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

Output:

97 | P a g e
Student Count: 0

Int Count: 0

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

Example: Enumerable.Range()

var intCollection = Enumerable.Range(10, 100);


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

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


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

Output:

Int Count: 100

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 99: 109

In the above example, Enumerable.Range(10, 100) creates collection with 100 integer
type elements with the sequential values starting from 10. First parameter

98 | P a g e
specifies the starting value of elements and second parameter specifies the
number of elements to create.

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

var intCollection = Enumerable.Repeat<int>(10, 100);


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

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


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

Output:

Int Count: 100

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 99: 10

In the above example, Enumerable.Repeat<int>(10, 100) creates collection with 100


integer type elements with the repeated value of 10. First parameter specifies the
values of all the elements and second parameter specifies the number of elements
to create.

99 | P a g e
Set operator: Distinct
LINQ Set operators perform some operation on one or two sequences (collections)
and produce a result set.

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.

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

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

LINQ Set operators

100 | P a g e
Distinct:
The Distinct extension method returns a new collection of unique elements from
the given collection.

Example: Distinct C#

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

var distinctStrings = strList.Distinct();

foreach(string str in strList)


Console.WriteLine(str);

Example: Distinct VB.Net

Dim strList = New List(Of string) From {"One", "Two", "Three", "Two", "Three" }

Dim distinctStr = strList.Distinct();

For Each str As string in strList


Console.WriteLine(str);
Next

Output:

One

Two

Three

The Distinct extension method doesn't compare values of class objects. You need
to implement IEqualityComparer interface in order to compare the values of class
objects.

Example: IEqualityComparer with Distinct in C#

public class Student


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

101 | P a g e
class StudentComparer : IEqualityComparer<Student>
{
public bool Equals(Student x, Student y)
{
if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentName.To
Lower())
return true;

return false;
}

public int GetHashCode(Student obj)


{
return obj.GetHashCode();
}
}

Now, you can pass above StudentComparer class in the Distinct extension method
as a parameter to compare the values:

Example: Distinct C#

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(Student std in distinctStudents)


Console.WriteLine(std.StudentName);

Output:

John

Steve

Bill

102 | P a g e
Ron

Distinct operator in Query Syntax:


The Distinct operator is Not Supported in C# Query syntax. However, you can
use Distinct method of query variable or wrap whole query into brackets and then
call Distinct().

Use the Distinct keyword in VB.Net query syntax:

Example: Distinct in query syntax VB.Net

Dim strList = New List(Of string) From {"One", "Three", "Two", "Two", "One" }

Dim distinctStr = From s In strList _


Select s Distinct

Set operator: Except


LINQ Set operators perform some operation on one or two sequences (collections)
and produce a result set.

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.

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

103 | P a g e
Except:
The Except() extension method requires two collections. One collection on which
Except method invoked and second collection which is passed as a parameter.
The Except method returns the elements from first collection which do not exist
in the second collection(parameter collection).

Example: Except in method syntax C#

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);

Example: Except in method syntax VB.Net

Dim strList1 = New List(Of string) From {"One", "Two", "Three", "Four", "Five" }
Dim strList2 = New List(Of string) From {"Four", "Five", "Six", "Seven", "Eight"}

Dim result = strList1.Except(strList2);

foreach(string str in result)


Console.WriteLine(str);

Output:

One

Two

Three

Except 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 Except method.

Implement IEqualityComparer interface for Student class as shown below:

Example: IEqualityComparer with Except method C#

public class Student

104 | P a g e
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}

class StudentComparer : IEqualityComparer<Student>


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

return false;
}

public int GetHashCode(Student obj)


{
return obj.GetHashCode();
}
}

Now, you can pass above StudentComparer class in Except extension method in
order to get the correct result:

Example: Except() with object type C#

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 }
};

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

foreach(Student std in resultedCol)


Console.WriteLine(std.StudentName);

Output:

105 | P a g e
John

Steve

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

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

LI
NQ Set operators

Set operator: Intersect


LINQ Set operators perform some operation on one or two sequences (collections)
and produce a result set.

106 | P a g e
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.

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

Intersect:
The Intersect extension method requires two collections - One collection on which
the Intersect method is invoked and a second collection which is passed as a
parameter. Intersect method returns the elements that exists in the both the
collections.

Example: Intersect in method syntax C#

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);

Example: Intersect in method syntax VB.Net

Dim strList1 = New List(Of string) From {"One", "Two", "Three", "Four", "Five" }
Dim strList2 = New List(Of string) From {"Four", "Five", "Six", "Seven", "Eight"}

Dim result = strList1.Intersect(strList2);

foreach(string str in result)


Console.WriteLine(str);

107 | P a g e
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 Student


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

class StudentComparer : IEqualityComparer<Student>


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

return false;
}

public int GetHashCode(Student obj)


{
return obj.GetHashCode();
}
}

Now, you can pass above StudentComparer class in the Intersect extension
method in order to get the correct result:

Example: Intersect operator C#

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 } ,

108 | P a g e
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 }
};

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

foreach(Student std in resultedCol)


Console.WriteLine(std.StudentName);

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:

109 | P a g e
LI
NQ Set operators

Set operator: Union


LINQ Set operators perform some operation on one or two sequences (collections)
and produce a result set.

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.

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

110 | P a g e
Union:
The Union extension method requires two collections, one collection on which the
Union method is invoked and a second collection, which is passed as a parameter.
The Union method returns distinct elements from both the collections.

Example: Union operator in method syntax C#

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.Union(strList2);

foreach(string str in result)


Console.WriteLine(str);

Example: Union operator in method syntax VB.Net

Dim strList1 = New List(Of string) From {"One", "Two", "Three", "Four", "Five" }
Dim strList2 = New List(Of string) From {"Four", "Five", "Six", "Seven", "Eight"}

Dim result = strList1.Union(strList2);

foreach(string str in result)


Console.WriteLine(str);

Output:

One

Two

Three

Four

Five

Six

111 | P a g e
Seven

Eight

The Union 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 Union method.

Implement IEqualityComparer interface for Student class as below:

Example: Union operator with IEqualityComparer:

public class Student


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

class StudentComparer : IEqualityComparer<Student>


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

return false;
}

public int GetHashCode(Student obj)


{
return obj.GetHashCode();
}
}

Now, you can pass above StudentComparer class in the Union extension method
to get the correct result:

Example: Union operator C#

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 }
};

112 | P a g e
IList<Student> studentList2 = new List<Student>() {
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};

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

foreach(Student std in resultedCol)


Console.WriteLine(std.StudentName);

Output:

John

Steve

Bill

Ron

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

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

113 | P a g e
LI
NQ Set operators

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.

SkipWhile Skips elements based on a condition until an element does not satisfy the condition. If the first element itsel
doesn't satisfy the condition, it then skips 0 elements and returns all the elements in the 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
doesn't satisfy the condition then returns an empty collection.

114 | P a g e
Skip:
The Skip() method skips the specified number of element starting from first
element and returns rest of the elements.

Example: Skip() in C#

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 skipResult = studentList.Skip(3);

Example: Skip() in VB.Net

Dim studentList = New List(Of Student) From {


New Student() With {.StudentID = 1, .StudentName = "John", .Age = 18},
New Student() With {.StudentID = 2, .StudentName = "Steve", .Age = 15},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 25},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 19}
}

Dim skipResult = studentList.Skip(3)

The skipResult in the above example contains following elements:

Ram

Ron

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.

Example: Skip operator in VB.Net

Dim skipResult = From s In studentList

115 | P a g e
Skip 3
Select s

SkipWhile:
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.

Example: SkipWhile in C#

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


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

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

foreach(string str in resultList)


Console.WriteLine(str);

Example: SkipWhile in VB.Net

Dim strList = New List(Of string) From {


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

Dim resultList = strList.SkipWhile(function(s) s.Length < 4);

For Each str As string in resultList


Console.WriteLine(str);
Next

Output:

116 | P a g e
Three

Four

Five

Six

SkipWhile also passes an index of current element in the lambda expression. The
following example of SkipWhile method skips elements till length of string
element is greater than its' index:

Example: SkipWhile with index in C#

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


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

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

foreach(string str in resultList)


Console.WriteLine(str);

Example: SkipWhile with index in VB.Net

Dim strList = New List(Of string) From {


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

Dim resultList = strList.SkipWhile(function(s, i) s.Length > i);

For Each str As string in strList


Console.WriteLine(str);
Next
Output:

117 | P a g e
Five

Six

Skip/SkipWhile operator in Query Syntax:


Skip & SkipWhile operator is NOT APPLICABLE 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().

Example: SkipWhile method in VB.Net

Dim strList = New List(Of string) From {


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

Dim skipWhileResult = From s In studentList


Skip While s.Length < 4
Select s

Output:

Three

Four

Five

Six

Partitioning Operators: Take & TakeWhile


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

118 | P a g e
Method Description

Skip Skips elements up to a specified position starting from the first element in a sequence.

SkipWhile Skips elements based on a condition until an element does not satisfy the condition. If the first element itsel
doesn't satisfy the condition, it then skips 0 elements and returns all the elements in the 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
doesn't satisfy the condition, it then returns an empty collection.

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

Example: Take() in method syntax C#

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 takeResult = studentList.Take(3);

Example: Take() in method syntax VB.Net

Dim studentList = New List(Of Student) From {


New Student() With {.StudentID = 1, .StudentName = "John", .Age = 18},
New Student() With {.StudentID = 2, .StudentName = "Steve", .Age = 15},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age = 25},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 19}
}

Dim takeResult = studentList.Take(3)

The takeResult in the above example contains following elements:

119 | P a g e
John

Steve

Bill

Query Syntax:
Take & TakeWhile operator is Not Supported in C# query syntax. However, you
can use Take/TakeWhile method on query variable or wrap whole query into
brackets and then call Take/TakeWhile().

Example: Take operator in query syntax VB.Net

Dim takeResult = From s In studentList


Take 3
Select s

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

Example: TakeWhile in C#

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


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

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

foreach(string str in resultList)


Console.WriteLine(str);

Example: TakeWhile in VB.Net

Dim strList = New List(Of string) From {

120 | P a g e
"One",
"Two",
"Three",
"Four",
"Five",
"Six" }

Dim resultList = strList.TakeWhile(function(s) s.Length < 4);

For Each str As string in resultList


Console.WriteLine(str);
Next

Output:

One

Two

TakeWhile also passes an index of current element in predicate function.


Following example of TakeWhile method skips elements till length of string
element is greater than its' index:

Example: TakeWhile in C#:

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);

Example: TakeWhile in VB.Net

Dim strList = New List(Of string) From {


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

121 | P a g e
Dim resultList = strList.TakeWhile(function(s, i) s.Length > i);

For Each str As string in strList


Console.WriteLine(str);
Next
Output:

One

Two

Three

Four

Conversion Operators:
The Conversion operators 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

122 | P a g e
Method Description

ToArray Converts a collection to an array

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#:

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);
}

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 } ,
};

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

123 | P a g e
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

As you can see in the above example AsEnumerable and AsQueryable methods
convert compile time type to IEnumerable and IQueryable respectively

Visit stackoverflow for detail information on AsEnumerable and AsQueryable


method.

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

Example: Cast operator in C#

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);
}

static void Main(string[] args)


{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,

124 | P a g e
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 } ,
};

var
ReportTypeProperties( studentArray);
ReportTypeProperties(studentArray.Cast<Student>());
ReportTypeProperties((IEnumerable<Student>)studentArray);
ReportTypeProperties(studentArray.AsEnumerable());
}
}

Output:

Compile-time type: Student[]

Actual type: Student[]

Compile-time type: IEnumerable`1

Actual type: Student[]

Compile-time type: IEnumerable`1

Actual type: Student[]

Compile-time type: IEnumerable`1

Actual type: Student[]

As you can see in the above example, studentArray.Cast<Student>() is the same


as(IEnumerable<Student>)studentArray but Cast<Student>() is more readable.

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


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

125 | P a g e
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.

Example: ToArray & ToList in C#

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


"One",
"Two",
"Three",
"Four",
"Three"
};

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

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

ToDictionary - Converts a Generic list to a generic dictionary:

Example: ToDictionary in C#:

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 }
};

//following converts list into dictionary where StudentId is a key


IDictionary<int, Student> studentDict = studentList.ToDictionary<Student, int>(s => s
.StudentID);

The following figure shows how studentDict in the above example contains a key-
value pair, where key is a StudentID and the value is Student object.

LI
NQ-ToDictionary Operator

126 | P a g e
Expression<TDelegate>:
We have already learned that the lambda Expression is assinged to the variable
of Func or Action type delegates to process over in-memory collections. The
compiler will convert the lambda expression assigned to Func or Action type
delegate into executable code at compile time.

LINQ introduced the Expression<TDelegate> type. Now, the lambda expression


can also be assigned to Expression<TDelegate>. The compiler will convert the
lambda expression that is assigned to Expression<TDelegate> into an Expression
tree. Remote LINQ providers like LINQ-to-SQL, EntityFramework or any other
LINQ query provider that implements IQueryable<T> interface uses the
Expression tree as a data structure to build a runtime query out of it.

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

Define 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;

Example: Define Func delegate for an expression in VB.Net

Dim isTeenAger As Func(Of Student, Boolean) = Function(s) s.Age > 12 And s.Age < 20

And now, you can convert the above Func type delegate into an Expression by
wrapping Func delegate with Expresson, as below:

127 | P a g e
Example: Define Expression in C#

Expression<Func<Student, bool>> isTeenAgerExpr = s => s.age > 12 && s.age < 20;

Example: Define Expression in VB.Net

Dim isTeenAgerExpr As Expression(Func(Of Student, Boolean)) = Function(s) s.Age > 12


And s.Age < 20

in the same way, you can also wrap an Action<t> type delegate with Expression
if you don't return a value from the delegate.

Example: Define Expression in C#

Expression<Action<Student>> printStudentName = s => Console.WriteLine(s.StudentName);

Example: Define Expression in VB.Net

Dim printStudentName As Expression(Action(Of Student) = Function(s) Console.WriteLine


(s.StudentName);

Thus, you can define Expression<TDelegate> type. Now, let's see how to invoke
delegate wrapped by an Expression<TDelegate>.

Invoke Expression<TDelegate>:
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#

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 teen = isTeenAger(new Student(){Age = 20});

Example: Invoke Expression in VB.Net

Dim isTeenAgerExpr As Expression(Of Func(Of Student, Boolean)) = Function(s) s.Age >


12 And s.Age < 20

128 | P a g e
'compile Expression using Compile method to invoke it as Delegate
Dim isTeenAger As Func(Of Student, Boolean) = isTeenAgerExpr.Compile()

Dim teen = isTeenAger(New Student() With {.Age = 20})

As mentioned before, an Expression is converted into an Expression Tree at


compile time. An expression tree can be used as a data structure by remote LINQ
providers such as LINQ-to-SQL, EntityFramework or any other provider that
implements the IQueryable<T> interface.

Expression and Func

Learn about the Expression tree in detail in the next section.

Expression Tree:
An Expression tree is a tree-like data structure, such as a list or queue, where
each node is an expression, a method call or a binary operation such as x < y. It
is an in-memory representation of a lambda expression. An Expression tree holds
the actual elements of the query itself, 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#

Expression<Func<Student, bool>> isTeenAgerExpr = s => s.age > 12 && s.age < 20;

The compiler will translate the above expression into the following expression
tree:

Example: Expression Tree in C#

Expression.Lambda<Func<Student, bool>>(
Expression.AndAlso(

129 | P a g e
Expression.GreaterThan(Expression.Property(pe, "Age"), Expression
.Constant(12, typeof(int))),
Expression.LessThan(Expression.Property(pe, "Age"), Expression.Co
nstant(20, typeof(int)))),
new[] { pe });

You can also build an expression tree manually. Let's see how to build an
expression tree for the following simple lambda expression:

Example: Func delegate in C#:

Func<Student, bool> isAdult = s => s.age >= 18;

This Func type delegate will be treated like the following method:

C#:

public bool function(Student s)


{
return s.Age > 18;
}

To create the expression tree, first of all, create a parameter expression where
Student is the type of the parameter and 's' is the name of the parameter as
below:

Step 1: Create Parameter Expression in C#

ParameterExpression pe = Expression.Parameter(typeof(Student), "s");

Now, use Expression.Property() to create s.Age expression where s is the


parameter and Age is the property name of Student. (Expression is an abstract
class that contains static helper methods to create the Expression tree manually.)

Step 2: Create Property Expression in C#

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

Now, create a constant expression for 18:

Step 3: Create Constant Expression in C#

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

Till now, we have built expression trees for s.Age (member expression) and 18
(constant expression). We now need to check whether a member expression is
130 | P a g e
greater than a constant expression or not. For that, use the
Expression.GreaterThanOrEqual() method and pass the member expression and
constant expression as parameters:

Step 4: Create Binary Expression in C#

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

Thus, we have built an expression tree for a lambda expression body s.Age >=
18. We now need to join the parameter and body expressions. Use
Expression.Lambda(body, parameters array) to join the body and parameter part
of the lambda expression s => s.age >= 18:

Step 5: Create Lambda Expression in C#

var isAdultExprTree = Expression.Lambda<Func<Student, bool>>(body, new[] { pe });

This way you can build an expression tree for simple Func delegates with a lambda
expression.

Example: Expression Tree in C#

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 isAdultExprTree = Expression.Lambda<Func<Student, bool>>(body, new[] { pe });

Example: Expression Tree in VB.Net

Dim pe As ParameterExpression = Expression.Parameter(GetType(Student), "s")


Dim mexp As MemberExpression = Expression.Property(pe, "Age")

Dim constant As ConstantExpression = Expression.Constant(18, GetType(Integer))

Dim body As BinaryExpression = Expression.GreaterThanOrEqual(mexp, constant)

Dim isAdultExprTree As Expression(Of Func(Of Student, Boolean)) = Expression.Lambda(O


f Func(Of Student, Boolean))(body, New ParameterExpression() {pe})

The following image illustrates the whole process of creating an expression tree:

131 | P a g e
Construct Expression Tree

Why do we need an 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 implementsIEnumerable<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 Whereextension
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

132 | P a g e
Func delegate is a raw executable code, so if you debug the code, you will find
that the Funcdelegate 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.

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:

Expression 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#

var parameters = isTeenAgerExpr.Parameters;

foreach (var param in parameters)


{
Console.WriteLine("\tParameter Name: {0}", param.Name);
Console.WriteLine("\tParameter Type: {0}", param.Type.Name );
}
var bodyExpr = isTeenAgerExpr.Body as BinaryExpression;

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


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);

133 | P a g e
Console.WriteLine("Return Type: {0}", isTeenAgerExpr.ReturnType);

Output:

Parameter Name: s

Parameter Type: Student

Expression Type: Lambda

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:

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.

134 | P a g e
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.

Expression Tree Process

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. 'To' operations of conversion
operators execute the given query and give the result immediately.

Method Syntax:
C#:

IList<Student> teenAgerStudents = studentList.Where(s => s.age > 12 && s.age < 20).To
List();

VB.Net:

Dim teenAgerStudents As IList(Of Student) = studentList.Where(Function(s) s.Age > 12


And s.Age < 20).ToList()

135 | P a g e
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:

Immediate Execution

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

C#:

IList<Student> teenAgerStudents = (from s in studentList


where s.age > 12 && s.age < 20
select s).ToList();

VB.Net:

Dim teenAgerStudents As IList(Of Student) = (From s In studentList _


Where s.Age > 12 And s.Age < 20 _
Select s).ToList()

You can see the result in the teenAgerStudents collection, as below:

Immediate Execution

Further Reading:
 Charlies' blog

136 | P a g e
 MSDN

The '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:

C#:
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 lowercaseStudentNames = from s in studentList


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

Output:

ram

Asron
you can see, the ToLower() method is used multiple times in the above query.
The following example use 'let' to introduce new variable 'lowercaseStudentName'
that will be then used in every where. Thus, let keyword to make the query more
readable.

Example: let keyword in C#


var lowercaseStudentNames = from s in studentList
let lowercaseStudentName = s.StudentName.ToLower()
where lowercaseStudentName.StartsWith("r")
select lowercaseStudentName;

137 | P a g e
Example: let keyword in VB.Net
Dim lowercaseStudentNames = From s In studentList
Let lowercaseStudentName = s.StudentName.ToLower()
Where lowercaseStudentName.StartsWith("r")
Select lowercaseStudentName;

Output:

ram

ron

The 'into' keyword:


We have already used the 'into' keyword in grouping. You can also use the 'into'
keyword to continue a query after a select clause.

Example: into keyword in LINQ


var teenAgerStudents = from s in studentList
where s.age > 12 && s.age < 20
select s
into teenStudents
where teenStudents.StudentName.StartsWith("B")
select teenStudents;

Output:

Bill

In the above query, the 'into' keyword introduced a new range


variable teenStudents, so the first range variable s goes out of scope. You can
write a further query after the into keyword using a new range variable.

The 'into' keyword in VB.Net used for grouping purposes.

Example: into keyword in LINQ VB.Net


Dim groupQuery = From s In studentList
Group By s.Age Into Group

138 | P a g e
Sample LINQ Queries:
In this section, you will learn some complex LINQ queries. We will use the
following Student and Standard collection for our queries.

C#:

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"}
};

Multiple Select and where operator:


C# - Method Syntax:

var studentNames = studentList.Where(s => s.Age > 18)


.Select(s => s)
.Where(st => st.StandardID > 0)
.Select(s => s.StudentName);

Output:

Steve

Ram

The following query returns Enumerable of anonymous object that has only
StudentName property:

C#:
139 | P a g e
var teenStudentsName = from s in studentList
where s.age > 12 && s.age < 20
select new { StudentName = s.StudentName };

teenStudentsName.ToList().ForEach(s => Console.WriteLine(s.StudentName));

Output:

John

Bill

Group By:
The following query returns list students group by StandardID:

C#:

var studentsGroupByStandard = from s in studentList


group s by s.StandardID into sg
orderby sg.Key
select new { sg.Key, sg };

foreach (var group in studentsGroupByStandard)


{
Console.WriteLine("StandardID {0}:", group.Key);

group.sg.ToList().ForEach(st => Console.WriteLine(st.StudentName ));


}

Output:

StandardID 0:

Ron

StandardID 1:

140 | P a g e
John

Steve

StandardID 2:

Bill

Ram

The output includes Ron who doesn't have any StandardID. So Ron falls under
StandardID 0.

To remove a student who doesn't have a StandardID, use a where operator before
the group operator:

C#:

var studentsGroupByStandard = from s in studentList


where s.StandardID > 0
group s by s.StandardID into sg
orderby sg.Key
select new { sg.Key, sg };

Output:

StandardID 1:

John

Steve

StandardID 2:

Bill

Ram

141 | P a g e
Left outer join:
Use left outer join to display students under each standard. Display the standard
name even if there is no student assigned to that standard.

C#:

var studentsGroup = from stad in standardList


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

foreach (var group in studentsGroup)


{
Console.WriteLine(group.StandardName);

group.Students.ToList().ForEach(st => Console.WriteLine(st.StudentName));


}

Output:

Standard 1:

John

Steve

Standard 2:

Bill

Ram

Standard 3:

In the following example of group by query, we sort the group and select only
StudentName:

142 | P a g e
C#:

var studentsWithStandard = from stad in standardList


join s in studentList
on stad.StandardID equals s.StandardID
into sg
from std_grp in sg
orderby stad.StandardName, std_grp.StudentName
select new {
StudentName = std_grp.StudentName,
StandardName = stad.StandardName
};

foreach (var group in studentsWithStandard)


{
Console.WriteLine("{0} is in {1}", group.StudentName, group.StandardName);
}

Output:

John is in Standard 1

Steve is in Standard 1

Bill is in Standard 2

Ram is in Standard 2

Sorting:
The following query returns list of students by ascending order of StandardID and
Age.

C#:

var sortedStudents = from s in studentList


orderby s.StandardID, s.age
select new {
StudentName = s.StudentName,
Age = s.age,
StandardID = s.StandardID };

sortedStudents.ToList().ForEach(s => Console.WriteLine("Student Name: {0}, Age: {1},


StandardID: {2}", s.StudentName, s.Age , s.StandardID));

143 | P a g e
Output:

Student Name: Ron, Age: 21, StandardID: 0

Student Name: John, Age: 18, StandardID: 1

Student Name: Steve, Age: 21, StandardID: 1

Student Name: Bill, Age: 18, StandardID: 2

Student Name: Ram, Age: 20, StandardID: 2

Inner Join:
C#:

var studentWithStandard = from s in studentList


join stad in standardList
on s.StandardID equals stad.StandardID
select new {
StudentName = s.StudentName,
StandardName = stad.StandardName
};

studentWithStandard.ToList().ForEach(s => Console.WriteLine("{0} is in {1}", s.Studen


tName, s.StandardName ));

Output:

John is in Standard 1

Steve is in Standard 1

Bill is in Standard 2

Ram is in Standard 2

144 | P a g e
Nested Query:
C#:

var nestedQueries = from s in studentList


where s.age > 18 && s.StandardID ==
(from std in standardList
where std.StandardName == "Standard 1"
select std.StandardID).FirstOrDefault()
select s;

nestedQueries.ToList().ForEach(s => Console.WriteLine(s.StudentName));

Output:

Steve

145 | P a g e

You might also like