This document provides an overview of LINQ (Language Integrated Query) in 3 sentences or less:
LINQ allows querying over local collections and data sources by using language integrated query syntax or methods like Where, Select, and OrderBy. It relies on concepts like generics, delegates, lambda expressions, and extension methods to define query behaviors in a clean, readable way. Mastering LINQ requires understanding how these underlying concepts work and fit together to enable powerful querying capabilities.
2. 2
LINQ
LINQ – The Quick Explanation
Sequences & Elements
IEnumerable
Lambda Expressions
Chaining Lambda expressions
Comprehension Queries
LINQ – The Long Explanation
Delegates
Lambda expressions
Generic methods
Func and Action delegates
Extension functions
LINQ
3. 3
LINQ – The Quick Explanation
LINQ = Language Integrated Query.
Allows you to write queries over
1. local collections e.g. Lists, Arrays that implement IEnumerable
2. data sources e.g. SQL database using objects that implement Iquerable
By queries we mean the ability to select and/or filter information from a collection or data
source
- e.g. select all males from a list of people or from a table containing people
Sequences & Elements
LINQ works on sequences and elements
Sequences : lists, array etc.. any object that implements IEnumerable (or Iqueryable for data
sources)
Element : each item in that sequence
E.g string[] names = {‘Tom’ , ‘Dick’, Harry’ }; names = sequence : Tom,Dick,Harry = elements
4. LINQ – The Quick Explanation
IEnumerable
4
LINQ works on collections that implement IEnumerable (and data sources that implement IQueryable)
=> provides a way to run a query on each item in the collection
1. IEnumerable provides methods to loop over a collection
when you use foreach (string name in names) you are indirectly using IEnumerable to iterate over
collection.
2. IEnumerable extension methods are provided for querying
Methods available for querying each item in collection : Query functions include: Select, where, orderby
NB: A query takes, as an input, a collection(sequence), and returns a transformed output collection
(collection in, collection out)
Input Collection Transform query New Output Collection
e.g. Get all items
where color = blue
5. LINQ – The Quick Explanation
IEnumerable
5
Collection in Transform Collection out
Query Function {..}
• where item = blue
• Select item into new diamond item
1. Input collection of items
2. Query (transform) function runs :
• visits each item in list in turn
• runs query to see if item makes it into new list
Queries functions include
- Where : user for filtering
- Select : used to select item or transform the item itself
- Orderby : used to order the items
3. Returns new collection containing items
- Note : the items themselves can be transformed
Transform
Function
6. LINQ – The Quick Explanation
Lambda Expressions
6
So how do we define that transform function???
We use a lambda expression
A lambda expression a short hand way of writing a function
is a lambda expression
This is a short hand way of saying
• Given an item n
• if n.length > 3
• Return true
In code this would look like this :
bool function(string n)
{
return (n.length > 3)
}
Note :
• the types (bool & string in this example)
are inferred.
• The return keyword is also inferred
n => n.Length > 3
7. LINQ – The Quick Explanation
Lambda Expressions : An Example
7
Lets look at an example :
string[] names = {"Tom" , "Dick", "Harry" };
IEnumerable< string> filterednames = names.Where(n=>n.Length > 3)
n => n.Length > 3
For each item n in names list if n.length > 3 is true
put it in the returned sequence (i.e filternames)
NB : n =>n.Length > 3 tells the where query how to do the filtering (how to build the returned sequence)
A lambda expression has the following form :
input parameters => expression/statements (e.g. n => n.Length > 3);.
n is the input parameter. In this case each name string in list (we are iterating over string array of names)
n.length > 3 is the statement returns true or false , If it returns true, ‘where’ method will put n into the
returned list (Note : expression/statement determines return type)
8. 8
LINQ – The Quick Explanation
Chaining Lambda expressions
string[] names = {"Tom" , "Dick", "Harry", "Mary" };
IEnumerable<string> filterednames = names.Where (n => n.Contains('a'))
.OrderBy (n => n.Length)
.Select (p => p.ToUpper());
//result = MARY, HARRY
LINQ queries can be chained one after another
This works because each query takes a sequence as an input and returns a sequence as an output
Where takes in a sequence (names) and return a sequence
This sequences is fed into OrderBy , which returns a sequence
This sequences is fed into select, which returns a sequence
Where (n => n.Contains('a'))
n is each name in list : if n contains an ‘a’ it will make it into the returned sequence
OrderBy (n => n.Length)
n is each name in list : returned list contains n ordered by length
Select (p => p.ToUpper() )
p is each name in list : returned list contains n converted to uppercase
Note : input is just a
place holder
Any name will do .. n, p
9. 9
LINQ – The Quick Explanation
Comprehension Queries
Comprehension Queries provide an alternative syntax to lambda queries
Query using Lambda Expressions
string[] names = {"Tom" , "Dick", "Harry", "Mary" };
IEnumerable<string> filterednames = names.Where (n => n.Contains('a'))
.OrderBy (n => n.Length)
.Select (p => p.ToUpper());
Same Query using comprehension Queries
string[] names = {"Tom" , "Dick", "Harry", "Mary" };
IEnumerable<string> filterednames1 = from n in names
where n.Contains('a')
orderby n.Length
select n.ToUpper();
Note : Unlike Lambda,
have to use same variable
name (n here) throughout
query
People who are familiar with SQL may feel more
comfortable using ‘comprehension queries’
10. 10
LINQ – The Quick Explanation
Some More Examples
Please see sample projects (from class) for more examples of LINQ queries
11. 11
LINQ – The Long Explanation
In order to fully understand LINQ you need to understand
Delegates
Lambda expressions
Generic methods
Func and Action delegates
Extension functions
LINQ
12. 12
Delegates
Up till now you have only passed types into and out of method
Void methodname ( int p1, string p2)
However you can also pass functions as parameters to functions (WTF!!!)
Void methodname ( int p1, function p2) not exactly right.. Actually pass delegate which is a reference to function
Delegates are used to pass functions around just like you pass variables around.
Void methodname(int p1, DelegateName p2)
{
int x = p2();
}
DelegateName will hold a reference to a function!
Inside methodname(), You can call p2 like you normally call a function : int x = P2();
In essence delegates allow you to treat functions just like you would treat a variable
Assigning it to another variable
Passing it as a parameter
13. 13
Delegates
//1. Declare delegate (will be used to hold ref to functions) looks just like function method, prepended with type Delegate
delegate int calcMethod (int x1, int x2);
//2. Declare 2 functions that exactly match delegate definition (delegate will hold reference to these)
static int addmethod (int n1, int n2)
{
return n1 + n2;
}
static int multiplymethod (int n1, int n2)
{
return n1 + n2;
}
//3. Declare a function that will accept delegate as parameter (in essence we can pass functions into the calculate function!!
static int Calculate(int n1, int n2, calcMethod fn)
{
return fn(n1, n2);
}
static void Main(string[] args)
{
int result = 0;
Console.WriteLine(“ To add the numbers (5,6) enter A, To multiply the numbers (5,6) enter M");
char choice = Console.ReadKey().KeyChar;
//Pass the add or multiply function into the calculate function
if(choice == 'a' || choice == 'A')
result = Calculate(5, 6, addmethod);
else
result = Calculate(5, 6, multiplymethod );
Console.WriteLine("Result = " + result.ToString() + "; Hit key to finish"); Console.ReadLine();
}
14. 14
Lambda Expression
In the previous slide we defined a delegate and 2 methods to match that delegate
delegate int calcMethod (int x1, int x2);
static int addmethod (int n1, int n2) static int multiplymethod (int n1, int n2)
{ {
return n1 + n2; return n1 * n2;
} }
We then wrote a method that would accept the delegate as a parameter (so that we could pass in the add or multiply function)
static int Calculate(int n1, int n2, calcMethod fn)
{
return fn(n1, n2);
}
We called the method as follows:
result = Calculate(5, 6, addmethod); or result = Calculate(5, 6, multiplymethod );
Lambda methods allow us to define what the function is ‘inplace’
result = Calculate(5, 6, (int x, int y) => { return x + y; }); or result = Calculate(5, 6, (int x, int y) => { return x * y; });
Advantage of Lambda methods
-Don’t have to declare functions somewhere else in code , you can write them ‘In place’
i.e. In this example, when using lambda methods, we can delete the addmethod() and multiplymethod().
We don’t’ need them!!! The lambda method describes the function and is written ‘in place’
Compiler can infer types so we can even shorten Lambda method above to
result = Calculate(5, 6, (x, y) => x + y); Can omit the ‘return’ for 1 line statement blocks (the x + y bit)
15. 15
Generic methods
A generic method accepts parameters & returns values of any type.
This means that instead of specifying what type (int, string etc..) each parameter is,
you use a placeholder that can accept any type
This allow you to write very ‘Generic’ methods : i.e methods that accept any type
// Declare a generic method : It is generic because it can accept and work on ANY type
// T is a placeholder. When the method it called , T will be replaced by the passed in type
// You declare types before the () and use them as your input and/or output and in your method body.
static void swap<T> (ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
//Calling the Generic method
Public Static Main()
{
int a = 1, b = 2;
string s1 = "string1", s2 = "string2";
//Using Generic Swap method to swap ints , and then the very same swap method to swap strings
swap<int> (ref a, ref b);
swap<string>(ref s1, ref s2);
}
16. 16
Func and Action delegates
Using Generics and delegates makes it possible to write a small set of extremely general
methods that can be used anywhere.
These are called Func and Actions delegates (provided by .Net is System namespace)
Func : set of delegate methods that take x inputs and return 1 output
Action : set of delegate methods that take x inputs and return 0 outputs (returns void)
delegate TResult Func <out TResult> (); //<- method that can return any type
delegate TResult Func <in T, out TResult> (T arg); //<- method that can take 1 input of any type & return any type
delegate TResult Func <in T1, in T2, out TResult> (T1 arg1, T2 arg2); //<- method that can take 2 input of any type & return any type
delegate TResult Func <in T1, in T2, int T3, out TResult> (T1 arg1, T2 arg2, T3 arg3);
.... and so on up to T6
delegate void Action (); //<- method that returns void
delegate void Action <in T> (T arg); //<- method that can take 1 input of any type & returns void
delegate void Action <in T1, in T2> (T1 arg1, T2 arg2); //<- method that can take 2 inputs of any type & returns void
delegate void Action <in T1, in T2, in T3> (T1 arg1, T2 arg2, T3 arg3);
.... and so on up to T6
17. 17
Extension methods
Extension methods allow us to ‘add’ methods to existing types/classes, without changing that
Type/Class.
•They are static methods contained in a static class
•The ‘this modifier’ is used to ‘mark them’ as extension methods of a particular class/Type
•The method can then be called as if it were a normal method contained in that class
Public static Class StringHelper //<- static class to hold extension metods for string Type
{
public static bool IsCapitalised( this string s) //using this on first parameter indicates its an extension method of that
{ // parameter type i.e IsCapitalised is an extension method of the class string
return char.IsUpper(s[0]); //is first letter a capital
}
}
This method can be called as follows
string s = “Dublin”;
bool isCapitalised = s.IsCapitalised( ) ; //IsCapitalised looks like its a method of string
//NB : looks like we are calling a method contained in the string class but it is actually an extension method
18. 18
LINQ
Generics , Func/Action delegates, Extension methods, & Lambda Expressions make LINQ query
methods (select, where ..) possible
The query methods use
1. Extension methods on IEnumerable (so you can write readable code like collection. where(..) )
2. Func/Action methods as parameters to query, that determines what work query should do
(what it filters, i.e what makes it into the returned list)
• (e.g ‘where’ method takes Func <in T, out TResult>
• T is the type of member in collection,
• TResult is a returned bool (to indicate if member is part of returned collection)
3. The Func/Action methods are passed in as Lambda Expressions (for readability)
Collection that implements Ienumerable Extension method on IEnumerable
Var filterednames = names.Where (n => n.Contains('a'))
Func delegate that accepts a type and returns a bool (Lambda expression used to
define the function referenced by delegate)