anguage Integrated Query, or LINQ, is a new Microsoft technology introduced with the .NET 3.5 framework. This Microsoft quote describes its purpose succinctly:
"Traditionally, queries against data are expressed as simple strings without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different query language for each type of data source: SQL databases, XML documents, various Web services, and so on. LINQ makes a query a first-class language construct in C# and Visual Basic. You write queries against strongly typed collections of objects by using language keywords and familiar operators."
The main tasks you can perform with LINQ include:
- Retrieve a subset of elements.
- Retrieve a sequence of elements transformed to a new type of object.
- Retrieve a singleton value about the source data, such as the largest element or the count of elements.
Traditionally, those types of operations are done on a database. While LINQ of course supports the database domain, the power of LINQ is that it can be used in the very same fashion when accessing data from any of these domains (linked to the MSDN reference pages for each technology):
The main advantages of using LINQ syntax include:
- Code is more concise and readable, especially when using multiple filters.
- You can filter, order, and group results with little coding.
- You can easily port a LINQ query from one data source to another with little or no modification.
|Author's Note: I assume you have had some exposure to LINQ in this article; if not, take a break from this article now and peruse some of the material available on Microsoft's site, particularly at the LINQ Home, or other tutorials.
This article explains some simple but useful applications of LINQ that lie at the heart of two moderately complex components that you can incorporate as building blocks in your production applications. The two components are quite different on the surface: one involves managing an application's external file resources, while the other involves creating and initializing items in a context menu.
What This Article Covers
- Techniques to Manage External File Resources: Package files with your applications and libraries as resources and then externalize them, i.e. unwrap them and use them as needed.
- Techniques to Manage Context Menus: Create an arbitrarily complex context menu, set states, and manage mutually exclusive sets of menu items using a menu builder that leverages LINQ.
- Using LINQ with .NET 2.0: Nominally for use with .NET 3.5, you can easily deploy LINQ into a .NET 2.0 environment (although you do need to compile the code with Visual Studio 2008).
What You Need
- Visual Studio 2008
- C# 3.0
- .NET Framework: 2.0 or higher
LINQ to Objects
This article focuses on useful LINQ to Objects techniques. In this context, an object
refers to any C# or Visual Basic object that implements the generic IEnumerable<T> interface; that is, collections, arrays, lists, dictionaries, or your own user-defined types. This covers a vast spectrum of the data types that deal with groups of data—even more than you might think at first glance—because some types that are not IEnumerable are convertible to types that are. To quote MSDN again:
"In a basic sense, LINQ to Objects represents a new approach to collections. In the old way, you had to write complex foreach loops that specified how to retrieve data from a collection. In the LINQ approach, you write declarative code that describes what you want to retrieve."
This is a remarkable achievement: it adds a layer of abstraction in your code where you can now describe what you want rather than how to go about it. Higher levels of abstraction lead to easier to read—and therefore more maintainable—code. Think of assembly language compared to C#, for example. Usually, greater abstraction has a cost of greater overhead, but my impression is that the overhead of LINQ is minimal, whether you use query expression syntax or method-based (also referred to as lambda) syntax.
The two types of syntax available for LINQ queries are exactly equivalent where they overlap, so which you use is merely a matter of personal preference. The performance question is moot; they perform exactly the same, because compilation converts expressions written in query syntax to lambda syntax as the first step. The lambda syntax, however, is much richer, particularly in C#. See Query Expression Syntax for Standard Query Operators for a reference chart that shows the subset of methods that may be invoked in query syntax in both C# and Visual Basic. If you are relatively new to LINQ, here's a great chart that shows how to write expressions in both query syntax and in lambda syntax side by side.
LINQ, the .NET Framework, and Extension Methods
LINQ, by default, requires the .NET 3.5 framework. At the time of writing, though, .NET 3.5 is still relatively new and it would be unrealistic to expect that all your potential users have it, particularly in corporate environments where upgrading infrastructure can be costly. If you only need LINQ-to-Objects and do not need the other flavors of LINQ listed above, the open source LINQBridge
library provides a clever solution that lets you operate with the .NET 2.0 framework. As explained on the LINQBridge page, LINQ queries do not depend on the 3.5 framework per se; rather, they depend on the presence of certain method signatures. It does not matter where those methods reside, so the LinqBridge.dll
library file supplies them in a 2.0 environment. You will need to use Visual Studio 2008 though; 2005 is not sufficient. VS2008 provides a multi-targeting feature, allowing you to specify which framework (2.0, 3.0, or 3.5) to compile to. To use LINQBridge, therefore, set the target framework on the Application page of your project properties to 2.0, and then add a reference to the LINQBridge.dll library to your project.
Since you must use Visual Studio 2008 you are therefore automatically using C# 3.0, independent of which framework version you target. One other key feature of C# 3.0 is extension methods
. Extension methods let you add methods to existing types without subclassing, recompiling, or modifying the original type in any way. You simply define a new method with a special signature, which you may then attach to an existing class with a simple using
statement. Oddly enough, you define such a method as a class
method yet use it like an instance
LINQ itself makes extensive use of extension methods for the standard query operators: Where, Select, GroupBy, etc. are all extension methods defined on the IEnumerable<T> type. Including a using System.Linq statement in your code exposes these methods for you to freely use in LINQ queries against IEnumerable<T> objects.
With the foundation of LINQ and extension methods laid you now have a good base upon which to build. The rest of this article will discuss a fairly simple technique involving both LINQ-to-Objects and extension methods. It is used at the heart of two moderate complexity components that could themselves be immediately incorporated as building blocks in a production application. What is interesting is that the two components are quite different on the surface: one involves managing an application's external file resources, while the other involves initializing choices in a context menu upon a right-click to open the menu.