Tiptoe Through the Tulips … LINQeses…es

As most can attest when launching into the world of WPF you have to jump in and hope you can figure out how to swim before you drown.  It has a huge learning curve but the end results are usually pretty amazing.

LINQ, on the other hand, you can slowly dip a toe in, see how tepid the water is, and then slowly immerse your whole body sliding into the warm 98 degree water.  Over the course of 7 months now I have been slowing dipping into the water called LINQ and wanted to give you a few examples where I found it particularly useful.  Unlike a cruel father I will not throw you into the water and hope you can swim but want to slowly lead you into the fold.

So what the hell is LINQ?  Well, it stands for Language INtegrated Query.  It is a way to query lists in code.  Really that’s it.  You’re f-in me Brian, aren’t you?  Yes, yes I am.  That is the fundamental idea behind LINQ but it can do so much more.

I suppose I should start with the var keyword.  You VB fans will cheer at this.  var is a variable declaration where the type of the variable is implicit in the constructor of the item being created.  This is similar to the Dim except that we are still statically typed here.  In .Net 3.5 the var keyword can be used anywhere you are defining a variable that the type can be implied.

Good Examples:

var myInt = 3;
var myDouble = 2.2;
var files = new List<FileInfo>();

Bad Examples:

var myDouble = 3;//not a double and myDouble will actually be an int
var myString = null;//type cannot be implied, will result in compile error

The easiest use for LINQ is in sorting.  No more needing to define an IComparable, just define your sort in an orderby clause.  LINQ has some similarities to writing SQL except that in order to facilitate compilation and intelli-sense the order of the query is a bit different.

Take this code for example:

//START CODE
var files = new List<FileInfo>();
var ArchiveDirectory = "C:Archive";
var archivedFiles = Directory.GetFiles(ArchiveDirectory);//will be of type string []
foreach (var filePath in archivedFiles)
{
    var fi = new FileInfo(filePath);
    files.Add(fi);
}
//now sort the file list based on last write time
var sortedFiles = from file in files orderby file.LastWriteTime descending select file;
//END CODE

Now, up until that last line it is standard C#.  The last line appears to be some sort of odd jacked-up sql.  If we break it down, however, you will see the power.

from file in files

basically for each file in our files list

orderby file.LastWriteTime

LastWriteTime is a property on FileInfo.  files is a list of FileInfo, therefore each file is a FileInfo object.  Intelli-sense is fully supported here so when you type in file and put the dot it shows you all the properties on file as if it were a standardly declared FileInfo.

descending

Like a standard DESC to an orderby clause.  Like sql it implicitly orders by ASC so if you want descending you have to add it.

select file

return the file that applies to the orderby clause.  The may seem a bit redundant and I would agree but it is still needed.

See?  Pretty simple.  No need to write an IComparable just order the list by the LastWriteTime.

So let’s take this a step further.

I have an example where I have three different tables all of which have the property “Name”.  I need to populate three different combo boxes with the values from each of the different tables.  Now I could write a whole bunch of code to do each table values and combo boxes separately but, well, nah!

Here we’re going to go a bit extreme.  Use a bit of LINQ, throw in some Generics and finally whip it all together with some Reflection.

Start with getting each list and ordering it by name

//START CODE
var sortedTypes = from type in new TypeService().GetAll() orderby type.Name select type;
var sortedFreqs = from freq in new FrequencyService().GetAll() orderby freq.Name select freq;
var sortedEvents = from event in new EventService().GetAll() orderby event.Name select event;
//END CODE

Well, that should be pretty straight forward now.  We can see the GetAll method of each service returns all the values from a table in the form of a list.  The we use the orderby clause in LINQ to sort it for us by the name.

Now let’s populate the combo boxes in the form:

//START CODE
PopulateComboBox<Type>(sortedTypes, cboType);
PopulateComboBox<Frequency>(sortedFreqs, cboFrequency);
PopulateComboBox<Event>(sortedEvents, cboEvent);
//END CODE

And thats all there is.  Pretty simple, huh?
Oh, you want to see what the hell PopulateComboBox does.  Fine, be that way.

//START CODE
private void PopulateComboBox<T>(System.Linq.IOrderedEnumerable<T> List, ComboBox Box)
{
    foreach (T val in List)
    {
        ComboBoxItem cbi = new ComboBoxItem
            {
                Content = FindReflectedProperty(val, "Name"),
                Tag = val
            };
        Box.Items.Add(cbi);
    }
}
//END CODE

As you can see we can’t take a var on the first value of the parameter since it’s type cannot be inferred.  As it would happen using the orderby clause in a LINQ query returns a list with the interface System.Linq.IOrderedEnumerable.  We use the good ole’ generics typeparam when calling the method so at runtime the code knows the type of T.  Additionally you can see that when creating the ComboBoxItem we use the new feature in 3.5 of setting properties on the objects when creating the object (really this happens right after the constructor is called).  The final bit to this is FindReflectedProperty.

//START CODE
public static object FindReflectedProperty(object Instance, string PropName)
{
    if (Instance == null)
        return null;
    foreach (PropertyInfo pi in Instance.GetType().GetProperties())
    {
        if (pi.Name == PropName)
            return pi.GetValue(Instance, null);
    }
    return null;
}
//END CODE

Getting the PropertyInfo on the instance passed in we are able to get the value of the property based on the property name.  Of course we can turn this method into more LINQ but I’ll leave that to the next in the series where we’ll dip our whole foot in, which should excite all you foot appreciators (or fetishes or whatever).  If you want to read ahead google LINQ Lambda.

And now your toe is wet, assuming you got this far.

Later ‘yall,
Brian

Previous Post

Next Post

Leave a Reply