What Is LINQ PDF
What Is LINQ PDF
What Is LINQ PDF
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 },
};
int i = 0;
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 } ,
};
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:
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 } ,
};
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
Readable code: LINQ makes the code more readable so other developers
compile time.
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.
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
Enumerable 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.
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).
// 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 }
};
// 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}
}
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.
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.
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.
The following example shows how to use LINQ method syntax query with the
IEnumerable<T> collection.
// 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 }
};
// 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}
}
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.
13 | P a g e
The above anonymous method can be represented using a Lambda Expression in
C# and VB.Net as below:
Let's see how the lambda expression evolved from the following anonymous
method.
The Lambda expression evolves from anonymous method by first removing the
delegate keyword and parameter type and adding a lambda operator:
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.
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:
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#
Function(s , 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:
s =>
{
int youngAge = 18;
Function(s)
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.
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.
18 | P a g e
Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;
Dim isStudentTeenAger As Func(Of Student, Boolean) = Function(s) s.Age > 12 And s.Age
< 20
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;
}
19 | P a g e
Example: Lamda expression assigned to Action delegate in C#
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:
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:
Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;
Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;
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.
21 | P a g e
Standard Query Operators in Method Syntax:
22 | P a g e
Classification Standard Query Operators
Concatenation Concat
Equality SequenceEqual
The following table lists all the filtering operators available in LINQ.
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);
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):
var filteredResult = studentList.Where(s => s.Age > 12 && 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.
return false;
});
Output:
John
Bill
Ron
26 | P a g e
var filteredResult = from s in studentList
where s.Age > 12
where s.Age < 20
select s;
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.
27 | P a g e
mixedList.Add(new Student() { StudentID = 1, StudentName = "Bill" });
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
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#
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.
29 | P a g e
A sorting operator arranges the elements of the collection in ascending or
descending order.
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.
30 | P a g e
Dim orderByResult = From s In studentList
Order By s.StudentName
Select s
Bill
John
Ram
Ron
Steve
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.
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#
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 }
};
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.
33 | P a g e
};
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.
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 following example shows how to use ThenBy and ThenByDescending method
for second level sorting:
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:
thenByDescResult would contain following elements. Please notice that Ram with
age 20 comes before Ram with age 18 because it has used ThenByDescending.
You can use ThenBy and ThenByDescending method same way in VB.Net as
below:
36 | P a g e
Example: ThenBy & ThenByDescending VB.Net
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
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:
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.
38 | P a g e
var groupedResult = from s in studentList
group s by s.Age;
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.
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
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.
42 | P a g e
foreach(Student s in group) //Each group has a inner collection
Console.WriteLine("Student Name: {0}", s.StudentName);
}
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
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.
C#:
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.
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
select ...
46 | P a g e
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};
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 ...
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.
Output:
Standard 1:
John,
Moin,
Standard 2:
Bill,
49 | P a g e
Ram,
Standard 3:
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.
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.
Console.WriteLine(item.standardName)
51 | P a g e
Next
Next
Output:
Standard 1:
John,
Moin,
Standard 2:
Bill,
Ram,
Standard 3:
into groupedCollection
select ...
52 | P a g e
Example: GroupJoin Query Syntax C#
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.
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.
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.
// iterate selectResult
foreach (var item in selectResult)
Console.WriteLine("Student Name: {0}, Age: {1}", item.Name, item.Age);
Output:
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:
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
Select Many:
The SelectMany operator projects sequences of values that are based on a
transform function and then flattens them into one sequence.
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
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.
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.
bool isAnyStudentTeenAger = studentList.Any(s => s.age > 12 && s.age < 20);
Output:
true
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.
58 | P a g e
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value,
IEqualityComparer<TSource> comparer);
The above example works well with primitive data types. However, it will not work
with a custom class. Consider the following example:
C#:
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.
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;
}
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:
So thus, you have to use comparer class in order to get corrent result from
Contains extension method for custom classes.
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
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}
}
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:
The Aggregate method performs an accumulate operation. Aggregate extension
method has the following overload methods:
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);
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.
63 | P a g e
Dim strList As IList(Of String) = New List(Of String) From {
"One",
"Two",
"Three",
"Four",
"Five"
}
The following example uses string as a seed value in the Aggregate extension
method.
// 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 }
};
// 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:
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.
// 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 }
};
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
// 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}
}
Console.log(commaSeparatedStudentNames);
Output:
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 }
};
Output:
Output:
67 | P a g e
Average Age of Student: 17.4
int Count<TSource>();
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#
68 | P a g e
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age = 20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}
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 }
};
Output:
Number of Students: 3
// 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}
}
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.
In the following example, Max returns maximum age from the studentList
collection:
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}
}
Output:
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#:
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 }
};
71 | P a g e
Console.WriteLine("Student ID: {0}, Student Name: {1}", studentWithLongName.S
tudentID, studentWithLongName.StudentName);
}
}
Output:
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.
Output:
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.
// 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}
}
Output:
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}
}
Output:
87
Element Operators:
Element operators return a particular element from a sequence (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.
// 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);
//throws ArgumentOutOfRangeException
var student3 = studentList.ElementAt(6);
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.
// 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 object-Bill from 3rd place(zero based index)
Dim student1 = studentList.ElementAtOrDefault(2)
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.
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.
// 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 firstTeenAgerStudent = studentList.First(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("First TeenAger Student Name : {0}", firstTeenAgerStudent.StudentNa
me);
Output:
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.
// 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 firstTeenAgerStudent = studentList.FirstOrDefault(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:
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.
// 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 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();
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.
Last:
The Last() method returns the last element of a collection, or the last element
that satisfies the specified condition.
// 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 lastTeenAgerStudent = studentList.Last(s => s.Age > 12 && s.Age < 20);
83 | P a g e
Console.WriteLine("Last TeenAger Student Name : {0}", lastTeenAgerStudent.StudentName
);
Output:
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.
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 lastTeenAgerStudent = studentList.LastOrDefault(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("Last TeenAger Student Name : {0}", lastTeenAgerStudent.StudentName
);
Output:
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'.
// 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 lastTeenStudent = query.LastOrDefault(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("First TeenAger Student Name : {0}", lastTeenAgerStudent.StudentNam
e);
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
);
Output:
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.
87 | P a g e
public static TSource Single<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.
// 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 singleTeenAgerStudent = studentList.Single(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("Single TeenAger Student Name : {0}", singleTeenAgerStudent.Student
Name);
}
/ throws InvalidOperationException as collection contains more than one element
88 | P a g e
Dim singleStudent = studentList.Single();
Output:
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 } ,
};
var singleTeenAgerStudent = studentList.Single(s => s.Age > 12 && s.Age < 20);//throw
s InvalidOperationException because studentList contains multiple teenager students
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.
// 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 }
};
VB.Net:
90 | P a g e
Console.WriteLine("Single integer greater than 10: {0}", intVal);
Output:
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.
// 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;
Student teenAgerStudent = query.SingleOrDefault(s => s.Age > 12 && s.Age < 20);
Console.WriteLine("TeenAger Student Name : {0}", teenAgerStudent.StudentName);
91 | P a g e
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age = 15}
}
Output:
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.
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" };
Output:
true
Example: SequenceEqual in C#
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.
93 | P a g e
if (x.StudentID == y.StudentID && x.StudentName.ToLower() == y.StudentNam
e.ToLower())
return true;
return false;
}
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
Five
Six
Generation Operators:
Generation operators create a new sequence (collection).
Method Description
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#
Output:
Count: 1
Element: null
Example: DefaultIfEmpty C#
Output:
96 | P a g e
Count: 1
Element: 0
Output:
Count: 1
Element: Bill
Empty:
The Empty method generates an empty collection of IEnumerable<T> type.
Example: Enumerable.Empty()
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()
Output:
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
..
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
Output:
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
..
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
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:
100 | P a g e
Distinct:
The Distinct extension method returns a new collection of unique elements from
the given collection.
Example: Distinct C#
Dim strList = New List(Of string) From {"One", "Two", "Three", "Two", "Three" }
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.
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;
}
Now, you can pass above StudentComparer class in the Distinct extension method
as a parameter to compare the values:
Example: Distinct C#
Output:
John
Steve
Bill
102 | P a g e
Ron
Dim strList = New List(Of string) From {"One", "Three", "Two", "Two", "One" }
Set
Operators Usage
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).
Dim strList1 = New List(Of string) From {"One", "Two", "Three", "Four", "Five" }
Dim strList2 = New List(Of string) From {"Four", "Five", "Six", "Seven", "Eight"}
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.
104 | P a g e
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}
return false;
}
Now, you can pass above StudentComparer class in Except extension method in
order to get the correct result:
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
106 | P a g e
Set
Operators Usage
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.
Dim strList1 = New List(Of string) From {"One", "Two", "Three", "Four", "Five" }
Dim strList2 = New List(Of string) From {"Four", "Five", "Six", "Seven", "Eight"}
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.
return false;
}
Now, you can pass above StudentComparer class in the Intersect extension
method in order to get the correct result:
108 | P a g e
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
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
Operators Usage
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.
Dim strList1 = New List(Of string) From {"One", "Two", "Three", "Four", "Five" }
Dim strList2 = New List(Of string) From {"Four", "Five", "Six", "Seven", "Eight"}
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.
return false;
}
Now, you can pass above StudentComparer class in the Union extension method
to get the correct result:
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 }
};
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
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#
Ram
Ron
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#
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:
117 | P a g e
Five
Six
Output:
Three
Four
Five
Six
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.
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().
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#
120 | P a g e
"One",
"Two",
"Three",
"Four",
"Five",
"Six" }
Output:
One
Two
121 | P a g e
Dim resultList = strList.TakeWhile(function(s, i) s.Length > i);
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).
Method Description
122 | P a g e
Method Description
class Program
{
ReportTypeProperties( studentArray);
ReportTypeProperties(studentArray.AsEnumerable());
ReportTypeProperties(studentArray.AsQueryable());
}
}
123 | P a g e
Output:
As you can see in the above example AsEnumerable and AsQueryable methods
convert compile time type to IEnumerable and IQueryable respectively
Cast:
Cast does the same thing as AsEnumerable<T>. It cast the source object into
IEnumerable<T>.
class Program
{
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:
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.
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.
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:
Func<Student, bool> isTeenAger = s => s.Age > 12 && s.Age < 20;
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;
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.
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.
Expression<Func<Student, bool>> isTeenAgerExpr = s => s.age > 12 && s.age < 20;
//Invoke
bool teen = isTeenAger(new Student(){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()
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.
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:
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:
This Func type delegate will be treated like the following method:
C#:
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:
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:
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:
This way you can build an expression tree for simple Func delegates with a lambda
expression.
The following image illustrates the whole process of creating an expression tree:
131 | P a g e
Construct 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:
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:
If you debug the code, Expression delegate will be represented as shown below:
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:
133 | P a g e
Console.WriteLine("Return Type: {0}", isTeenAgerExpr.ReturnType);
Output:
Parameter Name: s
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:
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.
Method Syntax:
C#:
IList<Student> teenAgerStudents = studentList.Where(s => s.age > 12 && s.age < 20).To
List();
VB.Net:
135 | P a g e
Query Syntax:
C#:
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#:
VB.Net:
Immediate Execution
Further Reading:
Charlies' blog
136 | P a g e
MSDN
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 }
};
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.
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
Output:
Bill
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#:
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 };
Output:
John
Bill
Group By:
The following query returns list students group by StandardID:
C#:
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#:
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#:
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#:
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#:
143 | P a g e
Output:
Inner Join:
C#:
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#:
Output:
Steve
145 | P a g e