Learn The Basics Of LINQ
(Oct 09 2007 - 08:15:50 PM
by Timothy Khouri
) - [print article
LINQ (Language INtegrated Query) is a powerful but misunderstood new language feature brought to us in the .NET framework version 3.5 (C# 3.0 and VB 9). Even though this is a new feature, it already has some huge misconceptions (such as thinking LINQ is a replacement to SQL). This article will teach you how to use LINQ (the language itself), where LINQ can save you a lot of time and will cover some basic concepts of Extension Methods and Lambda expressions.
The Need for LINQ
At first, when I didn't understand LINQ, I couldn't appreciate why we needed (or why anyone wanted) it. LINQ seemed very limited in usefulness, and I, like many of my colleagues, bashed it in ignorance. Now, due to understanding the semantics and benefits of the language, I've come to love it and wonder how I lived without it.
LINQ does not allow us to do anything new, as far as functionality goes. Really, if you wanted to make the argument of a 'real programmer', you could do all of this same functionality by writing encyclopedias of C code (heck, might as well just write it in assembly for "performance" reasons). But, LINQ does create a new way of looking at enumerations of data, and gives out-of-the-box functionality for them.
I realize that the above paragraphs might seem vague, so I'll get right into real examples that I have used as well as some odd examples that you might not have thought about as being 'queryable objects'.
Baby Steps - Basic LINQ Queries
Let's look at some very simple examples of LINQ so that we can have a basis to grow on. Let's pretend that we have a user control that has a variable amount of TextBoxes added to it (based on some database query or whatever). Our user control might have other controls (Buttons, Literals and the like), and we want to disable all of the TextBoxes if the user doesn't have security permissions to edit these controls. Please keep in mind that this is a hypothetical scenario at this point just so we can see some basic LINQ (in this case, LINQ to Objects).
Now, you can do this a few ways. Because the number of TextBoxes is dynamic we would possibly do something like this:
foreach (Control myChildControl in this.Controls)
if (myChildControl is TextBox)
((TextBox)myChildControl).Enabled = false;
The above code isn't really that bad, but I for one don't like that I have to loop through all of my controls, check the type, cast it to the type that I just checked for, and then set my property. So, let's see how LINQ will not only "pretty up" my code, but will also make more sense to us programmers:
var myChildTextBoxes = from myChildControl in this.Controls
where myChildControl is TextBox
foreach (TextBox myChildTextBox in myChildTextBoxes)
myChildTextBox.Enabled = false;
This LINQ approach is much cleaner. It's clear from the start that you want to work with a list of TextBoxes only. Secondly, you aren't type checking, then re-type casting. Now, you might argue that you could avoid the second type-cast by using an "as" keyword and checking for nulls, or you could say that you don't like how many lines of code this takes. Those are some valid claims, but if you are thinking that, then apparently you have a short attention span (as I mentioned above that this is just to get you a little familiar with the language syntax).
Step Two - Querying Unconventional Data Sources
Once you begin to use LINQ a bit more in you're C# (or VB), you'll begin to think of 'data sources' in a different way. For instance, you may see a directory (a folder on your computer) as a data source of files. You can even start to look at your list of running processes as a data source. Really, no enumeration is safe!
What if you were to make a web application that allowed you to upload and download files from your home machine? Let's say you had a DropDownList that would show a list of the files in the specified directory, perhaps with a button that lets you download it. How would you go about populating that DropDownList with clean file names for the "Text" property and perhaps the path for the "Value" property? I'll go a step further and say that this is what you're DropDownList looks like in ASP.NET:
<asp:DropDownList ID="MyFilesList" runat="server"
DataTextField="FileName" DataValueField="FullPath" />
Well, you could create you're own custom class that has a FileName property and a FullPath property. Then you could make a generic list of that class, loop through the files in a Directory.GetFiles method, add an entry for each file, set the list as the DataSource of the DropDownList and data bind. That's a whole lot of nasty that I'm not even going to show the code for (really, because I never want to write nasty code like that again). Here's what I would do using LINQ:
this.MyFilesList.DataSource = from file in Directory.GetFiles(somePath)
FileName = Path.GetFileName(file),
FullPath = file
All I can say after that is "Go LINQ GO!" and of course "case closed!"
Extension Methods and Lambda Expressions
One more part to LINQ is the heavy use of Extension Methods and Lambda expressions to accomplish this beautiful language enhancement. If you remember our original example of disabling the TextBoxes, then you're going to love one of the 50 STANDARD OPERATORS that are brought to you just by including a reference to the System.Linq namespace! Check this out:
foreach (TextBox myChildTextBox in this.Controls.OfType<TextBox>())
myChildTextBox.Enabled = false;
Don't check you're MSDN... there is no method called "OfType" on the ControlCollection class. But, because the ControlCollection class implements the IEnumerable interface, it automatically gets all of the extension methods that LINQ has kindly given to any enumeration (such as "OfType" which I am using above).
LINQ can be done one of two ways (or a combination of both): query expressions or method expressions. The difference between the two is only a syntax difference, as they ultimately compile into the same thing. Example:
var textBoxes = from control in this.Controls
where control is TextBox select control;
var textBoxes = this.Controls.OfType<TextBox>();
Lambda expressions come into play when you want to perform another standard operation such as "SUM" or "MAX". Here's an example that I have used recently. I wanted to make a property that displayed the "TotalBill" of an object that had child "orders" in it. Here's how lambda helped out:
public decimal TotalBill
return this.Orders.Sum(order => order.Price);
If you're not quite familiar with lambda as of yet, you can get a better explaination of the above in a blog post I made not long ago: LINQ, Lamda and Extension Methods Work Together!
There is much more to say about LINQ, but I hope for now you have a basic understanding and appreciation for it. As I get more time, I'll talk about some deeper subjects with LINQ such as how to use it in an enterprise level application and how to gain performance and improve multi-developer cohesion with it.