Monday, 28 April 2008

c# 3.0 - putting it all together part 4

This is part 13 in the c# 3.0, didn't think it would take this long, you can find the landing page here.
This is also the last part in this series.  I guess I've reached what I wanted to do, show you the largest new features in .net 3.5 and how they are used in LINQ.  As always, feedback is welcomed :)

So, last time you got a list of LINQ operators, indicating if they are (non) deferred and (non) streaming. 
This post goes into some more detail on a few query operators.  As per the previous post, any deferred execution is done via an iterator, so I won't repeat that here - you can use reflector on the System.Core dll if you want to find out more about it.

 

Where
= filters  items into a sequence
= deferred
= the where method offers two implementations, one which has already been discussed in a previous post, and a second one:
public static IEnumerable<TSource> Where<TSource>( this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)
the overload method for Where receives an extra integer, which is actually the index from the item in the collection.

eg: List<string> names = new List<string>()  {"john","bob","tom"};
       var query = names.Where( (n,i) => i > 1); 

the output of this query will be tom, as he's the only name with an index > 1.

 

Select
= returns a sequence of S from a sequence of T
= deferred
= overloaded with indexed version (see above)

One thing is of note on the select method:
public static IEnumerable<S> Select<T, S>(  this IEnumerable<T> source,  Func<T, S> selector);

Func<T, S> => the selection does not need to return the same type
eg: List<Customer> customers = new List<<Customer>(){new Customer(){Name="Bob", Id="1"}, ... };
       var query = customers.Select( c => new {Name=c.Name});

 

SelectMany
= selects zero or more elements S for each element of an input sequence T
= deferred
= overloaded with indexed version (see above)

public static IEnumerable<S> SelectMany<T, S>(  this IEnumerable<T> source,  Func<T, IEnumerable<S>> selector);

eg: the following will return an IEnumerable with all the products in it

public class ProductCategory{
public List<Product> Products {get;set;}
}

List<ProductCategory> categories = new List<ProductCategory>(){...};
IEnumerable<Product> = categories.SelectMany(category => category.Products);

 

Join
= Correlates the elements of two sequences based on matching keys. The default equality comparer is used to compare keys
= deferred

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(   this IEnumerable<TOuter> outer,    IEnumerable<TInner> inner,     Func<TOuter, TKey> outerKeySelector,    Func<TInner, TKey> innerKeySelector,   Func<TOuter, TInner, TResult> resultSelector
)

eg: the following returns a sequence of items with two fields= CustomerId, OrderId

List<Customer> customers = new List<Customer>(){...}
List<Order> orders = new List<Order>(){...};

var query =
customers.Join(orders       
, customer => customer.Id   //key for customers is the ID
, order => order.CustomerId // key for the order is the CustomerID
, (customer, order) => new { CustomerId = customer.Id, OrderId = order.Id } // given a customer and an order, select the two id's
    );

0 comments: