Bnei Brak 51202 Writing “Where” By Hand static class EnumerableExtensions { public static IEnumerable Where this IEnumerable source, public IEnumerator GetEnumerator { return new Whe
Trang 1LINQ via C# 3.0
Chapter 3 – LINQ Query Operators
Trang 2© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Query Operators
• Why query operators?
• Developing query operators for
IEnumerable<T>
• Language integration
Trang 3What Are Query Operators
?
• Query operators are typically extension
methods that operate on a sequence of
elements
• Some query operators return a sequence
of elements, some return a single value
Trang 4© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Why Query Operators
?
• Query operators facilitate declarative
programming instead of imperative
ToList() .ForEach(
Console.WriteLine);
Becomes
Trang 5Developing Query Operators
• Most query operators are very
straightforward
• Let’s develop some query operators that
operate on IEnumerable<T>
– Where (filtering a sequence)
– Order (ordering a sequence)
– Select (projecting a sequence to another sequence) – Count (aggregating a sequence)
– First (first element)
Trang 6© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Writing “Where” By Hand
static class EnumerableExtensions {
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source,
public IEnumerator<T> GetEnumerator() {
return new WhereEnumerator<T>( );
Trang 7Compiler Magic To The Rescue
• C# 2.0 includes compiler support for
generating IEnumerable
implementations
• Just yield them! public static IEnumerable<int> Range(
int min, int
max) {
for (; min < max; ++min)
yield return min;
}
foreach (int num in Range(0, 100) )
Console.WriteLine(num);
Trang 8© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Where’s The Magic
?
• The compiler generates code (edited):
private sealed class <Range>d 0 :
IEnumerable<int>, IEnumerable,
IEnumerator<int>,
IEnumerator, IDisposable {
private int <>1 state;
private int <>2 current;
public int <>3 max;
public int <>3 min;
public int max;
public int min;
private bool MoveNext();
IEnumerator<int>
IEnumerable<int>.GetEnumerator();
int IEnumerator<int>.Current { get; }
//More code snipped
}
Trang 9Behind The Magic
private bool MoveNext() {
Trang 10© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Revisiting “Where
”
static class EnumerableExtensions {
public static IEnumerable<T> Where<T>(
this IEnumerable<T> source,
var numbers = Range(0, 100);
var evens = numbers Where ( i => i%2==0 );
var here is IEnumerable<int
>
Trang 11• To order a sequence, we must iterate it
first… (And rely on a sorting container)
public static IEnumerable<T> Order<T>(
this IEnumerable<T> source) {
SortedDictionary<T, bool> elements =
new SortedDictionary<T, bool>();
foreach (T elem in source)
elements.Add(elem, default(bool));
foreach (T key in elements.Keys)
yield return key;
}
Trang 12© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
foreach (T elem in source)
yield return projection(elem);
}
Trang 13Count, First
public static long Count<T>(
this IEnumerable<T> source) {
public static T First<T>(
this IEnumerable<T> source) {
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
return enumerator.Current;
//Throw: Empty source
}
Trang 14© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Our Operators In Action
• This gives us some room for
experimentation:
var numbers = Range(0, 100);
var query = numbers.Where(i => i % 2 == 0);
Console.WriteLine("{0} numbers, first: {1}",
Trang 15Deferred Execution
• Statements such as
var numbers = Range(0, 100);
var evens = numbers.Where(i => i%2==0);
provide deferred execution semantics
• The enumeration is not executed yet!
– foreach forces execution
– Our Order operator forces execution
– Our Count operator forces execution
Trang 16© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Deferred Execution
• This infers interesting consequences:
– We can produce infinite streams:
IEnumerable<int> Primes(int start) {
Trang 18© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Standard LINQ Query Operators
• LINQ (in System.Core.dll) provides
standard query operators for
IEnumerable<T>
– Filtering: Where, Skip, Take, Distinct, OfType
– Aggregation: Sum, Max, Min, Count, First, FirstOrDefault,
Single, SingleOrDefault, Last, LastOrDefault, All, Any, Aggregate, Contains
– Ordering: OrderBy, OrderByDescending, ThenBy,
ThenByDescending
– Grouping: GroupBy
– Projection: Select, Repeat, SelectMany, ToArray, ToList,
ToLookup, ToDictionary, Cast
– Miscellaneous: Reverse, Union, Intersect, Join, Range, Concat
Trang 19Standard LINQ Query Operators
• LINQ query operators are extension
methods in the static Enumerable class
• Can be combined with our own!
– As long as there’s no name collision
• Note: So far we have discussed LINQ to Objects query operators
– Other LINQ provides do not work with IEnumerable
Trang 20© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Examples Of LINQ Operators
var q = Enumerable Range (0, 100)
Select (i => new { Id=i,
Trang 21This Looks Familiar
• The SQL resemblance is obvious:
SELECT product_name, COUNT(*)
Trang 22© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Language Query Operators
• Language query operators are language keywords that are mapped to query
operators
– Not all query operators are accessible via keywords
• C# integrated query operators:
Trang 23Language Query Operators
Trang 24© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Syntactic Sugar
• Language query operators translate
directly to LINQ query operators
• Query operators can be mixed:
Trang 25Advanced Example: Joins
• Most SQL-like joins are unnecessary
because objects are often denormalized
var largeOrders =
from cust in customers
from order in cust.Orders
where order.Amount > THRESHOLD
select new { cust.Name,
order.Amount };
var largeOrders =
from order in orders
where order.Amount > THRESHOLD
join cust in customers
on order.CustomerId equals
cust.Id
Trang 26© Copyright SELA Software & Education Labs Ltd 14-18 Baruch Hirsch St Bnei Brak 51202
Advanced Example: Let
• let is a helper keyword for complex
};
Trang 27Chapter Summary
• Why query operators?
• Developing custom query operators
• Language integrated query operators