LINQ To Objects: C# Development
LINQ To Objects: C# Development
Chapter 11
C# Development
Contents
1. Introduction to LINQ
2. Using LINQ with arrays
3. Using LINQ with collections
4. LINQ under the hood
5. Additional LINQ techniques
2
1. Introduction to LINQ
What is LINQ?
The purpose of LINQ
LINQ variations
A few technical details
3
What is LINQ?
LINQ = "Language Integrated Query"
4
The Purpose of LINQ
LINQ provides a unified syntax for querying data
• Regardless of where the data is coming from
5
LINQ Variations
There are several LINQ variations currently
available:
• LINQ to objects
• LINQ to XML
• LINQ to DataSet
• LINQ to Entities
6
A Few Technical Details
LINQ queries use SQL-like syntax
• Via C# keywords such as select, from, where, etc.
• Can manipulate any data source that implements the
IEnumerable<T> generic interface
• LINQ queries are strongly typed
8
Overview
In this section, we'll show how to use LINQ to
query data in an array
• See the LinqOverArrays project
• Automatically references LINQ-related assemblies
9
Querying Arrays Without LINQ
Here's a traditional array-processing example
• Uses manual iteration / conditional logic
• Doesn't use LINQ
private static void DemoNonLinq()
private static void DemoNonLinq()
{
{
//
// Here's
Here's an
an array
array of
of strings.
strings.
string[] cities = { "Boston", "New York", "Dallas", "St. Paul", "Las Vegas" };
string[] cities = { "Boston", "New York", "Dallas", "St. Paul", "Las Vegas" };
// Get the cities that contain a space character.
// Get the cities that contain a space character.
string[] citiesWithSpaces = new string[cities.Length];
string[] citiesWithSpaces = new string[cities.Length];
for (int i = 0; i < cities.Length; i++)
for (int i = 0; i < cities.Length; i++)
{
{
if
if (cities[i].Contains("
(cities[i].Contains(" "))
"))
citiesWithSpaces[i]
citiesWithSpaces[i] == cities[i];
cities[i];
}}
10
Querying Arrays With LINQ
Here's the equivalent example using LINQ
private static void DemoLinq()
private static void DemoLinq()
{
{
// Here's an array of strings.
// Here's an array of strings.
string[] cities = { "Boston", "New York", "Dallas", "St. Paul", "Las Vegas" };
string[] cities = { "Boston", "New York", "Dallas", "St. Paul", "Las Vegas" };
//
// Use
Use aa LINQ
LINQ query
query expression
expression to
to get
get the
the cities
cities that
that contain
contain aa space
space character.
character.
var subset = from g in cities
var subset = from g in cities
where g.Contains(" ")
where g.Contains(" ")
orderby g.Length
orderby g.Length
ascending
ascending
select g;
select g;
Console.WriteLine("\nCities
Console.WriteLine("\nCities with
with spaces
spaces (using
(using LINQ):
LINQ): ");
");
foreach (var s in subset)
foreach (var s in subset)
Console.WriteLine("City:
Console.WriteLine("City: {0}",
{0}", s);
s);
}}
12
Deferred Execution
LINQ queries use a "deferred execution" model
• Executed when you enumerate the query, not when
you create it
• Therefore, if you enumerate a query several times, the
query will be executed afresh each time
private static void DemoDeferredExecution()
private static void DemoDeferredExecution()
{
{
int[] examMarks = { 62, 75, 85, 59, 96, 80 };
int[] examMarks = { 62, 75, 85, 59, 96, 80 };
// Get the "A" grades, i.e. >= 70.
// Get the "A" grades, i.e. >= 70.
var
var subset
subset == from
from mm in
in examMarks
examMarks where
where mm >=
>= 70
70 select
select m;
m;
Console.WriteLine("\nA-grade
Console.WriteLine("\nA-grade exams
exams (LINQ
(LINQ query
query is
is executed
executed here):");
here):");
foreach (var m in subset)
foreach (var m in subset)
Console.WriteLine("Mark: {0}", m);
Console.WriteLine("Mark: {0}", m);
// Change some data in the array.
// Change some data in the array.
examMarks[0]
examMarks[0] == 99;
99;
Console.WriteLine("\nA-grade
Console.WriteLine("\nA-grade exams
exams (LINQ
(LINQ query
query is
is executed
executed AGAIN
AGAIN here):");
here):");
foreach (var m in subset)
foreach (var m in subset)
Console.WriteLine("Mark:
Console.WriteLine("Mark: {0}",
{0}", m);
m);
}
}
13
Immediate Execution
If you want to execute a query immediately:
• Invoke the ToArray<T>() extension method
Executes the query and places the result in a T[] array
• Or invoke the ToList<T>() extension method
Executes the query and places the result in a List<T>
private static void DemoImmediateExecution()
private static void DemoImmediateExecution()
{
{
int[]
int[] examMarks
examMarks == {{ 62,
62, 75,
75, 85,
85, 59,
59, 96,
96, 80
80 };
};
//
// Execute
Execute query
query immediately,
immediately, and
and get
get result
result as
as int[].
int[].
int[] arrayOfGradeAs
int[] arrayOfGradeAs = =
(from m in examMarks where m >= 70 select m).ToArray<int>();
(from m in examMarks where m >= 70 select m).ToArray<int>();
// Get data RIGHT NOW as List<int>.
// Get data RIGHT NOW as List<int>.
List<int> listOfGradeAs =
List<int> listOfGradeAs =
(from m in examMarks where m >= 70 select m).ToList<int>();
(from m in examMarks where m >= 70 select m).ToList<int>();
}
}
14
3. Using LINQ with Collections
Overview
Querying generic collections
Querying raw collections
Filtering data
15
Overview
In this section, we'll show how to use LINQ to
query data in a collection
• See the LinqOverCollections project
16
Querying Generic Collections
You can use generic collections in LINQ queries
• Generic collections implement IEnumerable<T>
private static void DemoLinqGenericCollection()
private static void DemoLinqGenericCollection()
{
{
// List<> of Product objects.
// List<> of Product objects.
List<Product>
List<Product> products
products == new
new List<Product>()
List<Product>()
{
{
new Product { Description = "3D HD-TV", Price = 1500, InStock = 3 },
new Product { Description = "3D HD-TV", Price = 1500, InStock = 3 },
new Product { Description = "BlueRay Player", Price = 200, InStock = 10 },
new Product { Description = "BlueRay Player", Price = 200, InStock = 10 },
…
…
};
};
Console.WriteLine("Expensive
Console.WriteLine("Expensive products:");
products:");
var subset1 = from p in products where p.Price > 300 select p;
var subset1 = from p in products where p.Price > 300 select p;
foreach (var p in subset1)
foreach (var p in subset1)
{
{
Console.WriteLine("\t{0}", p.Description);
Console.WriteLine("\t{0}", p.Description);
}
}
Console.WriteLine("Scarce
Console.WriteLine("Scarce expensive
expensive products:");
products:");
var
var subset2
subset2 == from
from pp in
in products
products where
where p.Price
p.Price >> 300
300 &&
&& p.InStock
p.InStock << 55 select
select p;
p;
foreach (var p in subset2)
foreach (var p in subset2)
{{
Console.WriteLine("\t{0}", p.Description);
Console.WriteLine("\t{0}", p.Description);
}
}
}
}
17
Querying Raw Collections
You can't use raw collections in LINQ queries
• Raw collections don't implement IEnumerable<T>
• You must convert into an IEnumerable<T> collection
private static void DemoLinqGenericCollection()
private static void DemoLinqGenericCollection()
{
{
// Raw ArrayList of Product objects.
// Raw ArrayList of Product objects.
ArrayList
ArrayList products
products == new
new ArrayList()
ArrayList()
{{
new
new Product
Product {{ Description
Description == "3D
"3D HD-TV",
HD-TV", Price
Price == 1500,
1500, InStock
InStock == 33 },},
new
new Product
Product {{ Description
Description == "BlueRay
"BlueRay Player",
Player", Price
Price == 200,
200, InStock
InStock == 10
10 },
},
…
…
};
};
// Transform ArrayList into an IEnumerable<T> collection.
// Transform ArrayList into an IEnumerable<T> collection.
var enumerable = products.OfType<Product>();
var enumerable = products.OfType<Product>();
Console.WriteLine("Expensive
Console.WriteLine("Expensive products
products (from
(from raw
raw collection
collection originally):");
originally):");
var subset = from p in enumerable where p.Price > 300 select p;
var subset = from p in enumerable where p.Price > 300 select p;
foreach (var p in subset)
foreach (var p in subset)
{
{
Console.WriteLine("\t{0}", p.Description);
Console.WriteLine("\t{0}", p.Description);
}
}
}
}
18
Filtering Data
You can filter data in a collection, to retrieve only
those objects of a specific type
• Use the OfType<T>() extension method
private
private static
static void
void DemoFilter()
DemoFilter()
{
{
// Raw ArrayList of various object types.
// Raw ArrayList of various object types.
ArrayList myStuff = new ArrayList()
ArrayList myStuff = new ArrayList()
{{
3,
3, 12,
12, 1964,
1964, true,
true, new
new Product(),
Product(), "super
"super swans"
swans"
};
};
// Transform ArrayList into an IEnumerable<int>, ignores the non-ints.
// Transform ArrayList into an IEnumerable<int>, ignores the non-ints.
IEnumerable<int> myInts = myStuff.OfType<int>();
IEnumerable<int> myInts = myStuff.OfType<int>();
Console.WriteLine("Ints from the raw collection:");
Console.WriteLine("Ints from the raw collection:");
foreach (int i in myInts)
foreach (int i in myInts)
{
{
Console.WriteLine("\t{0}",
Console.WriteLine("\t{0}", i);
i);
}
}
}
}
19
4. LINQ Under the Hood
Overview
Using C# query operators
LINQ extension methods
Using anonymous methods
Using lambda expressions
20
Overview
In this section, we'll explain what actually happens
when you use C# LINQ query operators
• See the LinqUnderTheHood project
21
Using C# Query Operators
Here's a simple example using C# query operators
• Nothing new here
private static void DemoOperators()
private static void DemoOperators()
{
{
string[]
string[] cities
cities == {{ "Boston",
"Boston", "New
"New York",
York", "Dallas",
"Dallas", "St.
"St. Paul",
Paul", "Las
"Las Vegas"
Vegas" };
};
// Create a LINQ query expression using C# query operators.
// Create a LINQ query expression using C# query operators.
var subset = from c in cities
var subset = from c in cities
where c.Contains(" ")
where c.Contains(" ")
orderby c.Length
orderby c.Length
select c;
select c;
Console.WriteLine("Cities with spaces (using C# query operators): ");
Console.WriteLine("Cities with spaces (using C# query operators): ");
foreach (var s in subset)
foreach (var s in subset)
Console.WriteLine("City: {0}", s);
Console.WriteLine("City: {0}", s);
}
}
22
LINQ Extension Methods
The C# query operators are short-hand syntax
• Under the cover, they represent extension methods
that are added to IEnumerable<T>
• Defined in the System.Linq.Enumerable class
• Located in the System.Core.dll assembly
For example:
where
where g.Contains("
g.Contains(" ")
")
24
Using Lambda Expressions
It's a small step from using anonymous methods
to using lambda expressions
private static void DemoLambdaExpressions()
private static void DemoLambdaExpressions()
{
{
string[]
string[] cities
cities == {{ "Boston",
"Boston", "New
"New York",
York", "Dallas",
"Dallas", "St.
"St. Paul",
Paul", "Las
"Las Vegas"
Vegas" };
};
// Pass lambda expressions into extension methods
// Pass lambda expressions into extension methods
var subset = cities.Where(c => c.Contains(" "))
var subset = cities.Where(c => c.Contains(" "))
.OrderBy(c => c.Length)
.OrderBy(c => c.Length)
.Select(c => c);
.Select(c => c);
Console.WriteLine("\nCities
Console.WriteLine("\nCities with
with spaces
spaces (using
(using lambda
lambda expressions):
expressions): ");
");
foreach (var s in subset)
foreach (var s in subset)
Console.WriteLine("City:
Console.WriteLine("City: {0}",
{0}", s);
s);
}}
25
5. Additional LINQ Techniques
Overview
Selecting full objects
Selecting specific fields
Selecting projections
Set-based operations
Aggregate operations
26
Overview
In this section, we'll show how to use some
additional LINQ techniques
• See the AdditonalLinqTechniques project
27
Selecting Full Objects
This example recaps how to query full objects
• Nothing new here
private static void DemoFullObjectQueries(Product[] products)
private static void DemoFullObjectQueries(Product[] products)
{
{
Console.WriteLine("Low-stock
Console.WriteLine("Low-stock product
product details:");
details:");
var
var prods
prods == from
from pp in
in products
products
where
where p.InStock
p.InStock << 55
select p;
select p;
foreach (var p in prods)
foreach (var p in prods)
Console.WriteLine("\t{0}",
Console.WriteLine("\t{0}", p);
p);
}}
28
Selecting Specific Fields
You can query specific fields from result objects
• Specify the required field in the select clause
private static void DemoSpecificFieldQueries(Product[] products)
private static void DemoSpecificFieldQueries(Product[] products)
{
{
Console.WriteLine("\nLow-stock
Console.WriteLine("\nLow-stock product
product prices:");
prices:");
var
var prices
prices == from
from pp in
in products
products
where
where p.InStock
p.InStock << 55
select p.Price;
select p.Price;
foreach (var p in prices)
foreach (var p in prices)
Console.WriteLine("\t{0:c}",
Console.WriteLine("\t{0:c}", p);
p);
}}
29
Selecting Projections
You can query "projections" from result objects
• A projection is an anonymous type
• Contains the properties specified in the select clause
private static void DemoProjectionQueries(Product[] products)
private static void DemoProjectionQueries(Product[] products)
{
{
Console.WriteLine("\nLow-stock products and prices:");
Console.WriteLine("\nLow-stock products and prices:");
var projs = from p in products
var projs = from p in products
where p.InStock < 5
where p.InStock < 5
select
select new
new {{ p.Description,
p.Description, p.Price
p.Price };
};
foreach (var p in projs)
foreach (var p in projs)
Console.WriteLine("\t{0}, {1:c}", p.Description, p.Price);
Console.WriteLine("\t{0}, {1:c}", p.Description, p.Price);
}
}
30
Set-Based Operations (1 of 2)
There are numerous extension methods that allow
you to perform set-based operations on queries
• Think "Venn-diagrams"
//
// Teams
Teams either
either of
of us
us likes…
likes…
var
var union = (from t in myTeams
union = (from t in myTeams select
select t).Union(from
t).Union(from t2
t2 in
in yourTeams
yourTeams select
select t2);
t2);
//
// Distinct
Distinct concatenation
concatenation of
of my
my teams
teams and
and your
your teams…
teams…
var
var distinct = (from t in myTeams select t).Concat(from t2
distinct = (from t in myTeams select t).Concat(from t2 in
in yourTeams
yourTeams select
select t2)
t2)
.Distinct();
.Distinct();
32
Aggregate Operations
LINQ provides various "aggregate" extension
methods
• Familiar concept for SQL developers
private
private static
static void
void DemoAggregates()
DemoAggregates()
{{
double[] winterTemps = { 2.0, -3.3, 8, -4, 0, 8.2 };
double[] winterTemps = { 2.0, -3.3, 8, -4, 0, 8.2 };
Console.WriteLine("\nAggregate
Console.WriteLine("\nAggregate query
query results:");
results:");
Console.WriteLine("Max:
Console.WriteLine("Max: {0:f2}", (from tt in
{0:f2}", (from in winterTemps
winterTemps select
select t).Max());
t).Max());
Console.WriteLine("Min:
Console.WriteLine("Min: {0:f2}",
{0:f2}", (from
(from tt in
in winterTemps
winterTemps select
select t).Min());
t).Min());
Console.WriteLine("Avg: {0:f2}", (from t in winterTemps select t).Average());
Console.WriteLine("Avg: {0:f2}", (from t in winterTemps select t).Average());
Console.WriteLine("Sum:
Console.WriteLine("Sum: {0:f2}",
{0:f2}", (from
(from tt in
in winterTemps
winterTemps select
select t).Sum());
t).Sum());
}
}
33
Summary
Introduction to LINQ
Using LINQ with arrays
Using LINQ with collections
LINQ under the hood
Additional LINQ techniques
34