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.

Examples of good use:

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

Examples of bad use:

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:

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;

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

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;

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:

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

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

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);
    }
}

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.

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;
}

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

Leave a Reply

Your email address will not be published. Required fields are marked *

FormatException

928 East Plymouth Drive Asbury Park, NJ 07712