LINQ to Objects for the .NET developer

Custom select

This article was originally published in VSJ, which is now part of Developer Fusion.

The nature of the Select depends on the nature of the data item. For example, if the item takes the form of a row of a table then a select can pick out individual columns. If the data item is an array then it can select individual elements. You can see that selecting part of the data item could be a complex operation. It helps greatly to know how LINQ works in terms of extension methods in understanding what it does and how to make use of it. For example the definition of one overlay of the Select extension method is:

public static IEnumerable<TResult>
    Select<TSource, TResult>(
    	this IEnumerable<TSource> source,
    	Func<TSource, TResult> selector
)

You can now clearly see that you have to specify a source type and a result type and a function that does the conversion between the two types. When you write a C# query expression using Select all you do is specify the transformation function and let the compiler work out the types of the source and result data. For example,

var q = from i in col where i > 250
    select i*2;

The final select now creates a function:

Func<int, int> MySelect=i->i*2;

…and passes, as a lambda expression, in the call to the Select method which is:

var q = col.
    Where<int>(i => i > 250).
    Select<int,int>(i=>i*2) ;

A little thought reveals that this mechanism is more sophisticated than it looks. For example, you can call methods defined in the source data type to perform more complicated data transformation. For example,

var q2 = col.
    Where<int>(i => i > 250).
    Select<int,string>(i=>i.ToString());
foreach (string o in q2)
{
    MessageBox.Show(o);
}

More Selection

Understanding how the query expression is converted into calls to the query extension methods greatly clarifies how LINQ works and what you can do with it. If you want to stay with a clear design you should always use Select as a “projection operator”, that is it should reduce the data item to something that is a subset of itself. For example, if the data item is a struct then the select should specify which fields are to be extracted and returned in a “smaller” struct. This is a common and interesting task so let’s look at another simple example of select.

First we need a class or struct to hold the data:

public struct Contact
{
    public string name { get; set; }
    public string address1 { get; set; }
    public int phone { get; set; }
}

The default property implementations allow us to initialise a List of such structs directly:

List<Contact> AddressBook=new
    List<Contact>(){
    new Contact(){
    	name=”mike”,
    	address1=”Anywhere1”,
    	phone=123},
    new Contact(){
    	name=”nick”,
    	address1=”Anywhere2”,
    	phone=124},
    new Contact(){
    	name=”john”,
    	address1=”Anywhere3”,
    	phone=125}
};

This is another useful addition to C# 3.0. As List supports IEnumerator we can now move immediately to using LINQ to query it. To extract a single field, the name say, you would use a query something like:

var q = from N in AddressBook
    select N.name;
foreach ( var n in q)
{
    MessageBox.Show(n);
}

Notice the use of var to avoid having to state the data type. If you don’t want to use an anonymous type then you can replace the var with string. It is easy to see how this translates to the call to the select extension method which has to return just the single field as a string but how do you return multiple fields? The problem is that you don’t have a data type, i.e. a struct, that holds a subset of fields. You could define a suitable struct, but the standard solution is to create a new anonymous type on the fly:

var q = from N in AddressBook
    select new { N.name, N.phone };
foreach ( var n in q)
{
    MessageBox.Show(n.name +
    	n.phone.ToString());
}

You can see that the new facilities in C# 3.0 really are required to make LINQ look simple.

Other LINQs

Basically we have been looking at LINQ to objects, but the same principles apply to all the other implementations – LINQ to SQL, XML and ADO for example. You should now be in a position to see how these work even if you still need to dig out the details. What is even more impressive is that if you have a data source that LINQ doesn’t support you should be able to add it by implementing IEnnumerable.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Before software should be reusable, it should be usable.” - Ralph Johnson