LINQ
LINQ
LINQ queries return results as objects. It enables you to uses object-oriented approach on the result set and
not to worry about transforming different formats of results into objects.
The following example demonstrates a simple LINQ query that gets all strings from an array which contains 'a'.
// LINQ Query
var myLinqQuery = from name in names
where name.Contains('a')
select name;
// Query execution
foreach(var name in myLinqQuery)
Console.Write(name + " "); //James Mohan
You will not get the result of a LINQ query until you execute it. LINQ query can be execute in multiple ways,
here we used foreach loop to execute our query stored in myLinqQuery. The foreach loop executes the query on
the data source and get the result and then iterates over the result set.
Thus, every LINQ query must query to some kind of data sources whether it can be array, collections, XML or
other databases. After writing LINQ query, it must be executed to get the result.
Why LINQ?
To understand why we should use LINQ, let's look at some examples. Suppose you want to find list of teenage
students from an array of Student objects.
Before C# 2.0, we had to use a 'foreach' or a 'for' loop to traverse the collection to find a particular object. For
example, we had to write the following code to find all Student objects from an array of Students where the
age is between 12 and 20 (for teenage 13 to 19):
2
Example: Use for loop to find elements from the collection in C# 1.0
class Student
{
public int StudentID { get; set; }
public String StudentName { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18 },
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 },
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 },
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 },
new Student() { StudentID = 5, StudentName = "Ron" , Age = 31 },
new Student() { StudentID = 6, StudentName = "Chris", Age = 17 },
new Student() { StudentID = 7, StudentName = "Rob",Age = 19 },
};
int i = 0;
class StudentExtension
{
public static Student[] where(Student[] stdArray, FindStudent del)
{
int i=0;
Student[] result = new Student[10];
foreach (Student std in stdArray)
if (del(std))
{
result[i] = std;
i++;
}
return result;
}
}
class Program
{
static void Main(string[] args)
{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
3
LINQ API
System.Linq namespace is included by default when you add a new class in Visual Studio.
LINQ queries uses extension methods for classes that implement IEnumerable or IQueryable interface.
The Enumerable and Queryable are two static classes that contain extension methods to write LINQ queries.
LINQ Query Syntax
4
There are two basic ways to write a LINQ query to IEnumerable collection or IQueryable data sources.
1. Query Syntax or Query Expression Syntax
2. Method Syntax or Method Extension Syntax or Fluent
Query Syntax
Query syntax is similar to SQL (Structured Query Language) for the database. It is defined within the C# or VB
code.
LINQ Query Syntax:
from <range variable> in <IEnumerable<T> or IQueryable<T> Collection>
namespace ConsoleApp10
{
internal class Program
{
static void Main(string[] args)
{
// string collection
IList<string> stringList = new List<string>() {
"C# Tutorials",
"VB.NET Tutorials",
"Learn C++",
"MVC Tutorials" ,
"Java"
};
"where" operator (aka clause) followed by a condition. This condition is generally expressed using lambda
expression.
LINQ query syntax always ends with a Select or Group clause. The Select clause is used to shape the data. You
can select the whole object as it is or only some properties of it. In the above example, we selected the each
resulted string elements.
In the following example, we use LINQ query syntax to find out teenager students from the Student collection
(sequence).
namespace ConsoleApp10
{
internal class Program
{
static void Main(string[] args)
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};
}
Output:
Teen age Students:
John
Bill
Ron
LINQ Method Syntax
In the previous section, you have learned about LINQ Query Syntax. Here, you will learn about Method syntax.
Method syntax (also known as fluent syntax) uses extension methods included in
the Enumerable or Queryable static class, similar to how you would call the extension method of any class.
The compiler converts query syntax into method syntax at compile time.
The following is a sample LINQ method syntax query that returns a collection of strings which contains a word
"Tutorials".
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp10
{
6
Console.WriteLine(isTeenAger(stud));
}
}
public class Student
{
Console.WriteLine(isTeenAger(stud));
8
}
}
Concatenation Concat
Equality SequenceEqual
}
Output
Teen age Students:
John
Bill
Ron
In the above sample query, the lambda expression body s.Age > 12 && s.Age < 20 is passed as a predicate
function Func<TSource, bool> that evaluates every student in the collection.
Alternatively, you can also use a Func type delegate with an anonymous method to pass as a predicate
function as below (output would be the same):
}
Output
John
Bill
Ron
Where extension method in Method Syntax
Unlike the query syntax, you need to pass whole lambda expression as a predicate function instead of just
body expression in LINQ method syntax.
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};
}
Output:
Teen age Students:
John
Bill
Ron
As mentioned above, the Where extension method also have second overload that includes index of current
element in the collection. You can use that index in your logic if you need.
The following example uses the Where clause to filter out odd elements in the collection and return only even
elements. Please remember that index starts from zero.
// Student collection
};
return true;
return false;
});
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.
The OfType operator filters the collection based on the ability to cast an element in a collection to a specified
type.
13
Use OfType operator to filter the above collection based on each element's type
public class Program
{
public static void Main()
{
IList mixedList = new ArrayList();
mixedList.Add(0);
mixedList.Add("One");
mixedList.Add("Two");
mixedList.Add(3);
mixedList.Add(new Student() { StudentID = 1, StudentName = "Bill" });
}
}
}
Output
One
Two
Bill
OfType in Method Syntax
You can use OfType<TResult>() extension method in linq method syntax as shown below.
Example: OfType in C#
var stringResult = mixedList.OfType<string>();
One
Two
A sorting operator arranges the elements of the collection in ascending or descending order. LINQ includes
following sorting operators.
OrderByDescending Sorts the collection based on specified fields in descending order. Only valid in method syntax.
ThenBy Only valid in method syntax. Used for second level sorting in ascending order.
ThenByDescending Only valid in method syntax. Used for second level sorting in descending order.
Reverse Only valid in method syntax. Sorts the collection in reverse order.
OrderBy
OrderBy sorts the values of a collection in ascending or descending order. It sorts the collection in ascending
order by default because ascending keyword is optional here. Use descending keyword to sort collection in
descending order.
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
var orderByDescendingResult = from s in studentList //Sorts the studentList collection in descending order
orderby s.StudentName descending
select s;
Console.WriteLine("Ascending Order:");
Console.WriteLine("Descending Order:");
}
15
Output
Ascending Order:
Bill
John
Ram
Ron
Steve
Descending Order:
Steve
Ron
Ram
John
Bill
OrderBy in Method Syntax
OrderBy extension method has two overloads. First overload of OrderBy extension method accepts the Func
delegate type parameter. So you need to pass the lambda expression for the field based on which you want to
sort the collection.
The second overload method of OrderBy accepts object of IComparer along with Func delegate type to use
custom comparison for sorting.
OrderBy Overload Methods:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
The following example sorts the studentList collection in ascending order of StudentName using OrderBy
extension method.
// Student collection
};
Console.WriteLine("Ascending Order:");
Console.WriteLine(std.StudentName);
Console.WriteLine("Descending Order:");
17
Console.WriteLine(std.StudentName);
Output
Ascending Order:
Bill
John
Ram
Ron
Steve
Descending Order:
Steve
Ron
Ram
John
Bill
Multiple Sorting
You can sort the collection on multiple fields seperated by comma. The given collection would be first sorted
based on the first field and then if value of first field would be the same for two elements then it would use
second field for sorting and so on.
Output
The ThenBy and ThenByDescending extension methods are used for sorting on multiple fields.
The OrderBy() method sorts the collection in ascending order based on specified field. Use ThenBy() method
after OrderBy to sort the collection on another field in ascending order. Linq will first sort the collection based
on primary field which is specified by OrderBy method and then sort the resulted collection in ascending order
again based on secondary field specified by ThenBy method.
The same way, use ThenByDescending method to apply secondary sorting in descending order.
The following example shows how to use ThenBy and ThenByDescending method for second level sorting:
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
Console.WriteLine("ThenBy:");
Console.WriteLine("ThenByDescending:");
Output
ThenBy:
ThenByDescending:
The grouping operators do the same thing as the GroupBy clause of SQL query. The grouping operators create
a group of elements based on the given key. This group is contained in a special type of collection that
implements an IGrouping<TKey,TSource> interface where TKey is a key value, on which the group has been
formed and TSource is the collection of elements that matches with the grouping key value.
Grouping Operators Description
GroupBy The GroupBy operator returns groups of elements based on some key value. Each group is represented by IGrouping<TKey, TElement> objec
ToLookup ToLookup is the same as GroupBy; the only difference is the execution of GroupBy is deferred whereas ToLookup execution is immediate.
20
GroupBy
The GroupBy operator returns a group of elements from the given collection based on some key value. Each
group is represented by IGrouping<TKey, TElement> object. Also, the GroupBy method has eight overload
methods, so you can use appropriate extension method based on your requirement in method syntax.
Note:
A LINQ query can end with a GroupBy or Select clause.
The result of GroupBy operators is a collection of groups. For example, GroupBy returns
IEnumerable<IGrouping<TKey,Student>> from the Student collection:
Retur
n type of GroupBy()
GroupBy in Query Syntax
The following example creates a groups of students who have same age. Students of the same age will be in
the same collection and each grouped collection will have a key and inner collection, where the key will be the
age and the inner collection will include students whose age is matched with a key.
// Student collection
};
group s by s.Age;
Output
Age Group: 18
Student Name: John
Student Name: Bill
Age Group: 21
Student Name: Steve
Student Name: Ron
Age Group: 20
Student Name: Ram
22
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.
// Student collection
};
}
23
}
Output
Age Group: 18
Student Name: John
Student Name: Bill
Age Group: 21
Student Name: Steve
Student Name: Ron
Age Group: 20
Student Name: Ram
ToLookup
ToLookup is the same as GroupBy; the only difference is GroupBy execution is deferred, whereas ToLookup
execution is immediate. Also, ToLookup is only applicable in Method syntax. ToLookup is not supported in
the query syntax.
}
24
}
public class Student{
}
Output
Age Group: 18
Student Name: John
Student Name: Bill
Age Group: 21
Student Name: Steve
Student Name: Ron
Age Group: 20
Student Name: Ram
The joining operators joins the two sequences (collections) and produce a result.
Joining Operators Usage
Join The Join operator joins two sequences (collections) based on a key and returns a resulted sequence.
GroupJoin The GroupJoin operator joins two sequences based on keys and returns groups of sequences. It is like Left Outer Join of SQL.
Join
The Join operator operates on two collections, inner collection & outer collection. It returns a new collection
that contains elements from both the collections which satisfies specified expression. It is the same as inner
join of SQL.
Join in Method Syntax
As you can see in the first overload method takes five input parameters (except the first 'this' parameter): 1)
outer 2) inner 3) outerKeySelector 4) innerKeySelector 5) resultSelector.
Let's take a simple example. The following example joins two string collection and return new collection that
includes matching strings in both the collection.
}
}
Output
One
Two
}
26
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.
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.
We have seen the Join operator in the previous section. The GroupJoin operator performs the same task as
Join operator except that GroupJoin returns a result in group based on specified group key. The GroupJoin
operator joins two sequences based on key and groups the result by matching key and then returns the
collection of grouped result and key.
GroupJoin requires same parameters as Join. GroupJoin has following two overload methods:
GroupJoin Overload Methods:
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter>
outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey>
innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);
As you can see in the first overload method takes five input parameters (except the first 'this' parameter): 1)
outer 2) inner 3) outerKeySelector 4) innerKeySelector 5) resultSelector. Please notice that resultSelector is of
Func delegate type that has second input parameter as IEnumerable type for inner sequence.
28
Now, let's understand GroupJoin using following Student and Standard class where Student class includes
StandardID that matches with StandardID of Standard class.
Example Classes
public class Program
{
public static void Main()
{
// Student collection
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18,
StandardID = 1 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21,
StandardID = 1 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18,
StandardID = 2 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20,
StandardID = 2 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};
Steve
Standard 2
Bill
Ram
Standard 3
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
into groupedCollection
select ...
The Select operator always returns an IEnumerable collection which contains elements based on a
transformation function. It is similar to the Select clause of SQL that produces a flat result set.
Now, let's understand Select query operator using the following Student class.
public class Student{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}
Select in Query Syntax
LINQ query syntax must end with a Select or GroupBy clause. The following example demonstrates select
operator that returns a string collection of StudentName.
Output
John
Moin
Bill
Ram
Ron
Select in Method Syntax
The Select operator is optional in method syntax. However, you can use it to shape the data. In the following
example, Select extension method returns a collection of anonymous object with the Name and Age property:
};
// iterate selectResult
Output
Quantifier Operators
The quantifier operators evaluate elements of the sequence on some condition and return a boolean value to
indicate that some or all elements satisfy the condition.
Operator Description
All Checks if all the elements in a sequence satisfies the specified condition
Any Checks if any of the elements in a sequence satisfies the specified condition
Contains Checks if the sequence contains a specific element
All
The All operator evalutes each elements in the given collection on a specified condition and returns True if all
the elements satisfy a condition.
};
bool areAllStudentsTeenAger = studentList.All(s => s.Age > 12 && s.Age < 20);
Console.WriteLine(areAllStudentsTeenAger);
Output
False
Any
Any checks whether any element satisfy given condition or not? In the following example, Any operation is
used to check whether any student is teen ager or not.
};
bool isAnyStudentTeenAger = studentList.Any(s => s.Age > 12 && s.Age < 20);
Console.WriteLine(isAnyStudentTeenAger);
Output
True
Quantifier Operator: Contains
The Contains operator checks whether a specified element exists in the collection or not and returns a boolean.
The Contains() extension method has following two overloads. The first overload method requires a value to
check in the collection and the second overload method requires additional parameter of IEqualityComparer
type for custom equalality comparison.
As mentioned above, the Contains() extension method requires a value to check as a input parameter. Type of
a value must be same as type of generic collection. The following example of Contains checks whether 10
exists in the collection or not. Please notice that int is a type of generic collection.
Console.WriteLine(result);
Output
35
False
Example two
};
Console.WriteLine(result);
x.StudentName.ToLower() == y.StudentName.ToLower())
return true;
return false;
return obj.GetHashCode();
Output
True
The aggregation operators perform mathematical operations like Average, Aggregate, Count, Max, Min and
Sum, on the numeric property of the elements in the collection.
Method Description
Aggregate Performs a custom aggregation operation on the values in the collection.
Average calculates the average of the numeric items in the collection.
Count Counts the elements in a collection.
LongCount Counts the elements in a collection.
Max Finds the largest value in the collection.
Min Finds the smallest value in the collection.
Sum Calculates sum of the values in the collection.
Aggregate
The Aggregate method performs an accumulate operation. Aggregate extension method has the following
overload methods:
Aggregate() Overloads:
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source,
Func<TSource, TSource, TSource> func);
The following example demonstrates Aggregate method that returns comma seperated elements of the string
list.
Console.WriteLine(commaSeperatedString);
}
Output
One, Two, Three, Four, Five
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.
Console.WriteLine(commaSeparatedStudentNames);
}
}
Output
Student Names: John,Moin,Bill,Ram,Ron,
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.
Console.WriteLine(commaSeparatedStudentNames);
}
}
Output
John,Moin,Bill,Ram,Ron
Average extension method calculates the average of the numeric items in the collection. Average method
returns nullable or non-nullable decimal, double or float value.
The following example demonstrate Agerage method that returns average value of all the integers in the
collection.
}
Output
Average: 20
You can specify an int, decimal, double or float property of a class as a lambda expression of which you want
to get an average value. The following example demonstrates Average method on the complex type.
Example: Average in Method Syntax C#
public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};
}
}
The Count operator returns the number of elements in the collection or number of elements that have satisfied
the given condition.
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.
Example: Count() - C#
public class Program
{
public static void Main()
{
IList<int> intList = new List<int>(){ 10, 21, 30, 45, 50 };
}
}
Output
Total Elements: 5
Even Elements: 3
Example 2
public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Moin", Age = 21 },
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 },
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 },
new Student() { StudentID = 5, StudentName = "Ron" , Age = 15 }
};
}
}
The Max() method returns the largest numeric element from a collection.
return 0;
});
Max returns a result of any data type. The following example shows how you can find a student with the
longest name in the collection:
Example: Max() in C#
}
}
return 0;
}
}
Output
Student ID: 5, Student Name: Steve
The Sum() method calculates the sum of numeric items in the collection.
return 0;
});
The following example calculates sum of all student's age and also number of adult students in a student
collection.
Previous
Next
The ElementAt() method returns an element from the specified index from a given collection. If the specified index is out of the range of a
collection then it will throw an Index out of range exception. Please note that index is a zero based index.
The ElementAtOrDefault() method also returns an element from the specified index from a collaction and if the specified index is out of
range of a collection then it will return a default value of the data type instead of throwing an error.
The following example demonstrates ElementAt and ElementAtOrDefault method on primitive collection.
}
}
Output
1st Element in intList: 10
1st Element in strList: One
2nd Element in intList: 21
2nd Element in strList: Two
3rd Element in intList: 30
3rd Element in strList:
10th Element in intList: 0 - default int value
10th Element in strList: - default string value (null)
intList.ElementAt(9) throws an exception: Index out of range
-------------------------------------------------------------
Run-time exception (line 29): Index was out of range. Must be non-negative and less than the size
of the collection.
Parameter name: index
Stack Trace:
[System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than t
he size of the collection.
Parameter name: index]
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionRe
source resource)
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Linq.Enumerable.ElementAt[TSource](IEnumerable`1 source, Int32 index)
at P
The First and FirstOrDefault method returns an element from the zeroth index in the collection i.e. the first
element. Also, it returns an element that satisfies the specified condition.
Element
Operators Description
First Returns the first element of a collection, or the first element that satisfies a condition.
FirstOrDefault Returns the first element of a collection, or the first element that satisfies a condition. Returns a default value if index is out of
range.
First and FirstOrDefault has two overload methods. The first overload method doesn't take any input parameter
and returns the first element in the collection. The second overload method takes the lambda expression as
predicate delegate to specify a condition and returns the first element that satisfies the specified condition.
First() Á FirstOrDefault() Overloads:
public static TSource First<TSource>(this IEnumerable<TSource> source);
The First() method returns the first element of a collection, or the first element that satisfies the specified
condition using lambda expression or Func delegate. If a given collection is empty or does not include any
element that satisfied the condition then it will throw InvalidOperation exception.
The FirstOrDefault() method does the same thing as First() method. The only difference is that it returns
default value of the data type of a collection if a collection is empty or doesn't find any element that satisfies
the condition.
}
}
Output
1st Element in intList: 7
1st Even Element in intList: 10
1st Element in strList:
emptyList.First() throws an InvalidOperationException
-------------------------------------------------------------
Run-time exception (line 20): Sequence contains no elements
Stack Trace:
}
}
Output
1st Element in intList: 7
1st Even Element in intList: 10
1st Element in strList:
1st Element in emptyList:
Be careful while specifying condition in First() or FirstOrDefault(). First() will throw an exception if a collection
does not include any element that satisfies the specified condition or includes null element.
If a collection includes null element then FirstOrDefault() throws an exception while evaluting the specified
condition. The following example demonstrates this.
}
}
Output
Run-time exception (line 12): Sequence contains no matching element
Stack Trace:
The Last() and LastOrDefault() extension methods returns the last element from the collection.
Element Operators Description
Last() Returns the last element from a collection, or the last element that satisfies a condition. Throws exception if no element found.
LastOrDefault() Returns the last element from a collection, or the last element that satisfies a condition. Returns a default value if no element found.
Method Signature:
public static TSource Last<TSource>(this IEnumerable<TSource> source);
The Last() method returns the last element from a collection, or the last element that satisfies the specified
condition using lambda expression or Func delegate. If a given collection is empty or does not include any
element that satisfied the condition then it will throw InvalidOperation exception.
The LastOrDefault() method does the same thing as the Last() method. The only difference is that it returns
default value of the data type of a collection if a collection is empty or doesn't find any element that satisfies
the condition.
}
}
Output
Last Element in intList: 87
Last Even Element in intList: 50
Last Element in strList: Five
emptyList.Last() throws an InvalidOperationException
-------------------------------------------------------------
Run-time exception (line 20): Sequence contains no elements
Stack Trace:
}
}
Output
Last Element in intList: 87
Last Even Element in intList: 50
Last Element in strList: Five
Last Element in emptyList:
Single and SingleOrDefault have two overload methods. The first overload method doesn't take any input
parameter and returns a single element in the collection. The second overload method takes the lambda
expression as a predicate delegate that specifies the condition and returns a single element that satisfies the
specified condition.
Single() returns the only element from a collection, or the only element that satisfies the specified condition. If
a given collection includes no elements or more than one elements then Single() throws
InvalidOperationException.
The SingleOrDefault() method does the same thing as Single() method. The only difference is that it returns
default value of the data type of a collection if a collection is empty, includes more than one element or finds
no element or more than one element for the specified condition.
}
}
Output
49
There is only one equality operator: SequenceEqual. The SequenceEqual method checks whether the number of
elements, value of each element and order of elements in two collections are equal or not.
If the collection contains elements of primitive data types then it compares the values and number of
elements, whereas collection with complex type elements, checks the references of the objects. So, if the
objects have the same reference then they considered as equal otherwise they are considered not equal.
The following example demonstrates the SequenceEqual method with the collection of primitive data types.
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#
Console.WriteLine(isStudentsEqual);
Console.WriteLine(isStudentsEqual);
}
Output
True
False
To compare the values of two collection of complex type (reference type or object), you need to implement
IEqualityComperar<T> interface as shown below.
Console.WriteLine(isEqual);
}
}
return false;
}
51
The Concat() method appends two sequences of the same type and returns a new sequence (collection).
Example: Concat in C#
public class Program
{
public static void Main()
{
IList<string> collection1 = new List<string>() { "One", "Two", "Three" };
IList<string> collection2 = new List<string>() { "Five", "Six"};
}
}
Output
One
Two
Three
Five
Six
The DefaultIfEmpty() method returns a new collection with the default value if the given collection on which
DefaultIfEmpty() is invoked is empty.
Another overload method of DefaultIfEmpty() takes a value parameter that should be replaced with default
value.
Example: DefaultIfEmpty C#
public class Program
{
public static void Main()
{
IList<string> emptyList = new List<string>();
}
}
Output
Count: 1
Value:
Count: 1
Value: None
LINQ includes generation operators DefaultIfEmpty, Empty, Range & Repeat. The Empty, Range & Repeat
methods are not extension methods for IEnumerable or IQueryable but they are simply static methods defined
in a static class Enumerable.
Method Description
Empty Returns an empty collection
Range Generates collection of IEnumerable<T> type with specified number of elements with sequential values, starting from first element.
Repeat Generates a collection of IEnumerable<T> type with specified number of elements and each element contains same specified value.
Empty
The Empty() method is not an extension method of IEnumerable or IQueryable like other LINQ methods. It is a
static method included in Enumerable static class. So, you can call it the same way as other static methods like
Enumerable.Empty<TResult>(). The Empty() method returns an empty collection of a specified type as shown
below.
public class Program
{
public static void Main()
{
var emptyCollection1 = Enumerable.Empty<string>();
var emptyCollection2 = Enumerable.Empty<Student>();
}
}
}
Output
Type: String[]
Count: 0
Type: Student[]
Count: 0
Range
The Range() method returns a collection of IEnumerable<T> type with specified number of elements and
sequential values starting from the first element.
Example: Enumerable.Range()
public class Program
53
{
public static void Main()
{
var intCollection = Enumerable.Range(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());
}
}
Output
Total Count: 10
Value at index 0 : 10
Value at index 1 : 11
Value at index 2 : 12
Value at index 3 : 13
Value at index 4 : 14
Value at index 5 : 15
Value at index 6 : 16
Value at index 7 : 17
Value at index 8 : 18
Value at index 9 : 19
Repeat
The Repeat() method generates a collection of IEnumerable<T> type with specified number of elements and
each element contains same specified value.
Example: Repeat
public class Program
{
public static void Main()
{
var intCollection = Enumerable.Repeat<int>(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());
}
}
Output
Total Count: 10
Value at index 0 : 10
Value at index 1 : 10
Value at index 2 : 10
Value at index 3 : 10
Value at index 4 : 10
Value at index 5 : 10
Value at index 6 : 10
Value at index 7 : 10
Value at index 8 : 10
Value at index 9 : 10
The following figure shows how each set operators works on the collections:
LINQ
Set operators
Distinct
The Distinct extension method returns a new collection of unique elements from the given collection.
Example: Distinct C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Two",
"Three" };
foreach(var i in distinctList2)
Console.WriteLine(i);
}
}
Output
One
Two
55
Three
1
2
3
4
5
The Distinct extension method doesn't compare values of complex type objects. You need to
implement IEqualityComparer<T> interface in order to compare the values of complex types. In the following
example, StudentComparer class implements IEqualityComparer<Student> to compare Student< objects.
}
}
return false;
}
LINQ: Except
The Except() method requires two collections. It returns a new collection with elements from the first collection
which do not exist in the second collection (parameter collection).
The Intersect extension method requires two collections. It returns a new collection that includes common
elements that exists in both the collection. Consider the following example.
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;
}
The Intersect operator is Not Supported in C# & VB.Net Query syntax. However, you can use the Intersect
method on a query variable or wrap whole query into brackets and then call Intersect().
The following figure shows how each set operators works on the collections:
58
The Union extension method requires two collections and returns a new collection that includes distinct
elements from both the collections. Consider the following example.
Example: Union() in C#
public class Program
{
public static void Main()
{
IList<string> strList1 = new List<string>() { "One", "Two", "three", "Four" };
IList<string> strList2 = new List<string>() { "Two", "THREE", "Four", "Five" };
Partitioning operators split the sequence (collection) into two parts and return one of the parts.
Method Description
Skip Skips elements up to a specified position starting from the first element in a sequence.
59
Method Description
SkipWhile Skips elements based on a condition until an element does not satisfy the condition. If the first element itself doesn't satisfy the condition, it then skips 0 ele
sequence.
Take Takes elements up to a specified position starting from the first element in a sequence.
TakeWhile Returns elements from the first element until an element does not satisfy the condition. If the first element itself doesn't satisfy the condition then returns a
Skip
The Skip() method skips the specified number of element starting from first element and returns rest of the
elements.
Example: Skip() - C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Four", "Five" };
}
}
Output
Three
Four
Five
Skip Operator in Query Syntax
The Skip & SkipWhile operator is Not Supported in C# query syntax. However, you can use Skip/SkipWhile
method on a query variable or wrap whole query into brackets and then call Skip/SkipWhile.
As the name suggests, the SkipWhile() extension method in LINQ skip elements in the collection till the
specified condition is true. It returns a new collection that includes all the remaining elements once the
specified condition becomes false for any element.
The SkipWhile() method has two overload methods. One method accepts the predicate of Func<TSource,
bool> type and other overload method accepts the predicate Func<TSource, int, bool> type that pass the
index of an element.
In the following example, SkipWhile() method skips all elements till it finds a string whose length is equal or
more than 4 characters.
Example: SkipWhile in C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>() {
"One",
60
"Two",
"Three",
"Four",
"Five",
"Six" };
}
}
Output
Three
Four
Five
Six
Partitioning operators split the sequence (collection) into two parts and returns one of the parts.
The Take() extension method returns the specified number of elements starting from the first element.
Example: Take() in C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Four",
"Five" };
Output
One
Two
TakeWhile
The TakeWhile() extension method returns elements from the given collection until the specified condition is
true. If the first element itself doesn't satisfy the condition then returns an empty collection.
The TakeWhile method has two overload methods. One method accepts the predicate of Func<TSource,
bool> type and the other overload method accepts the predicate Func<TSource, int, bool> type that passes
the index of element.
In the following example, TakeWhile() method returns a new collection that includes all the elements till it finds
a string whose length less than 4 characters.
Example: TakeWhile in C#
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>(){ "Three", "Four", "Five", "Hundred" };
61
}
}
Output
Three
In the above example, TakeWhile() includes only first element because second string element does not
satisfied the condition.
TakeWhile also passes an index of current element in predicate function. Following example of TakeWhile
method takes elements till length of string element is greater than it's index
}
}
Output
One
Two
Three
Four
Conversion Operators
The Conversion operators in LINQ are useful in converting the type of the elements in a sequence (collection).
There are three types of conversion operators: As operators (AsEnumerable and AsQueryable), To operators
(ToArray, ToDictionary, ToList and ToLookup), and Casting operators (Cast and OfType).
Method Description
AsEnumerable Returns the input sequence as IEnumerable<t>
Method Description
ToDictionary Puts elements into a Dictionary based on key selector function
The AsEnumerable and AsQueryable methods cast or convert a source object to IEnumerable<T> or
IQueryable<T> respectively.
ReportTypeProperties( studentArray);
ReportTypeProperties(studentArray.AsEnumerable());
ReportTypeProperties(studentArray.AsQueryable());
}
}
Cast
Cast does the same thing as AsEnumerable<T>. It cast the source object into IEnumerable<T>.
{
Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
Console.WriteLine("Actual type: {0}", obj.GetType().Name);
}
ReportTypeProperties(studentArray);
ReportTypeProperties(studentArray.Cast<Student>());
}
}
As the name suggests, ToArray(), ToList(), ToDictionary() method converts a source object into an array, List
or Dictionary respectively.
To operators force the execution of the query. It forces the remote query provider to execute a query and get
the result from the underlying data source e.g. SQL Server database.
public class Program
{
public static void Main()
{
IList<string> strList = new List<string>() {
"One",
"Two",
"Three",
"Four",
"Three"
};
}
}
64
Output
strList type: List`1
strArray type: String[]
newList type: List`1
Expression in LINQ
The lambda Expression can be assigned to the Func or Action type delegates to process over in-memory
collections. The .NET compiler converts the lambda expression assigned to Func or Action type delegate into
executable code at compile time.
LINQ introduced the new type called Expression that represents strongly typed lambda expression. It means
lambda expression can also be assigned to Expression<TDelegate> type. The .NET compiler converts the
lambda expression which is assigned to Expression<TDelegate> into an Expression tree instead of executable
code. This expression tree is used by remote LINQ query providers as a data structure to build a runtime query
out of it (such as LINQ-to-SQL, EntityFramework or any other LINQ query provider that implements
IQueryable<T> interface).
The following figure illustrates differences when the lambda expression assigned to the Func or Action delegate
and the Expression in LINQ.
We will learn Expression tree in the next section but first, let's see how to define and invoke an Expression.
Define an Expression
Take the reference of System.Linq.Expressions namespace and use an Expression<TDelegate> class to define
an Expression. Expression<TDelegate> requires delegate type Func or Action.
For example, you can assign lambda expression to the isTeenAger variable of Func type delegate, as shown
below:
Func<Student, bool> isTeenAger = s => s.Age > 12 && s.Age < 20;
Invoke an Expression
You can invoke the delegate wrapped by an Expression the same way as a delegate, but first you need to
compile it using the Compile() method. Compile() returns delegateof Func or Action type so that you can
invoke it like a delegate.
//Invoke
bool result = isTeenAger(new Student(){ StudentID = 1, StudentName = "Steve",
Age = 20});
Console.WriteLine(result);
}
}
Expression Tree
You have learned about the Expression in the previous section. Now, let's learn about the Expresion tree here.
Expression tree as name suggests is nothing but expressions arranged in a tree-like data structure. Each node
in an expression tree is an expression. For example, an expression tree can be used to represent mathematical
formula x < y where x, < and y will be represented as an expression and arranged in the tree like structure.
Expression tree is an in-memory representation of a lambda expression. It holds the actual elements of the
query, not the result of the query.
The expression tree makes the structure of the lambda expression transparent and explicit. You can interact
with the data in the expression tree just as you can with any other data structure.
Example: Expression in C#
public class Program
{
public static void Main()
{
ParameterExpression pe = Expression.Parameter(typeof(Student), "s");
}
}
We have seen in the previous section that the lambda expression assigned to Func<T> compiles into
executable code and the lambda expression assigned to Expression<TDelegate> type compiles into
Expression tree.
Executable code excutes in the same application domain to process over in-memory collection. Enumerable
static classes contain extension methods for in-memory collections that
implements IEnumerable<T> interface e.g. List<T>, Dictionary<T>, etc. The Extension methods in an
Enumerable class accept a predicate parameter of Func type delegate. For example, the Where extension
method accepts Func<TSource, bool> predicate. It then compiles it into IL (Intermediate Language) to
process over in-memory collections that are in the same AppDomain.
The following image shows Where extension method in Enumerable class includes Func delegate as a
parameter:
Func
delegate in Where
Func delegate is a raw executable code, so if you debug the code, you will find that the Func delegate will be
represented as opaque code. You cannot see its parameters, return type and body:
Func
delegate in debug mode
Func delegate is for in-memory collections because it will be processed in the same AppDomain, but what
about remote LINQ query providers like LINQ-to-SQL, EntityFramework or other third party products that
provides LINQ capabilities? How would they parse lambda expression that has been compiled into raw
executable code to know about the parameters, return type of lambda expression and build runtime query to
process further? The answer is Expression tree.
67
If you debug the code, Expression delegate will be represented as shown below:
Expr
ession Tree in debug mode
Now you can see the difference between a normal delegate and an Expression. An expression tree is
transparent. You can retrieve a parameter, return type and body expression information from the expression,
as below:
LINQ query for LINQ-to-SQL or Entity Framework is not executed in the same app domain. For example, the
following LINQ query for Entity Framework is never actually executed inside your program:
68
It is first translated into an SQL statement and then executed on the database server.
The code found in a query expression has to be translated into an SQL query that can be sent to another
process as a string. For LINQ-to-SQL or Entity Frameworks, that process happens to be an SQL server
database. It is obviously going to be much easier to translate a data structure such as an expression tree into
SQL than it is to translate raw IL or executable code into SQL because, as you have seen, it is easy to retrieve
information from an expression.
Expression trees were created for the task of converting code such as a query expression into a string that can
be passed to some other process and executed there.
Queryable static class includes extension methods that accept a predicate parameter of Expression type. This
predicate expression will be converted into an Expression Tree and then will be passed to the remote LINQ
provider as a data structure so that the provider can build an appropriate query from the expression tree and
execute the query.
Expr
ession Tree Process
Deferred execution means that the evaluation of an expression is delayed until its realized value is actually
required. It greatly improves performance by avoiding unnecessary execution.
Deferred execution is applicable on any in-memory collection as well as remote LINQ providers like LINQ-to-
SQL, LINQ-to-Entities, LINQ-to-XML, etc.
Deferred Execution
In the above example, you can see the query is materialized and executed when you iterate using the foreach
loop. This is called deferred execution. LINQ processes the studentList collection when you actually access each
object from the collection and do something with it.
Deferred Execution returns the Latest Data
To check whether deferred execution returns the latest data each time, add one more teen ager student after
the foreach loop and check the teenager student list:
As you can see, the second foreach loop executes the query again and returns the latest data. Deferred
execution re-evaluates on each execution; this is called lazy evaluation. This is one of the major advantages
of deferred execution: it always gives you the latest data.
Implementing Deferred Execution
You can implement deferred execution for your custom extension methods for IEnumerable using
the yield keyword of C#.
For example, you can implement custom extension method GetTeenAgerStudents for IEnumerable that returns
a list of all students who are teenagers.
public class Program
{
public static void Main()
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 12 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};
select s;
Immediate execution is the reverse of deferred execution. It forces the LINQ query to execute and gets the
result immediately. The 'To' conversion operators execute the given query and give the result immediately.
Method Syntax
In the following example, ToList() extension method executes the query immediately and returns the result.
C#:
var teenAgerStudents = from s in studentList
where s.age > 12 && s.age < 20
select s;
The above query will not execute immediately. You won't find any result as shown below:
Im
mediate Execution
Query Syntax doesn't support 'To' operators but can use ToList(), ToArray() or ToDictionary() for immediate
execution as below:
71
C#:
IList<Student> teenAgerStudents = (from s in studentList
where s.age > 12 && s.age < 20
select s).ToList();
let keyword
The 'let' keyword is useful in query syntax. It projects a new range variable, allows re-use of the expression
and makes the query more readable.
For example, you can compare string values and select the lowercase string value as shown below:
Use into keyword in LINQ query to form a group or to continue a query after a select clause.
Output
Bill