|
LINQ, which stands for Language Integrated Query, is almost like one of those trick hologram stickers like you used to get on the side of an ET happy mea..uh..I'm not that old, honest... Anyway, if you look at it from one angle, it seems to have one purpose and style, and if you look at it from another angle, it seems to have yet another purpose, style, and power.
LINQ combines the expressive nature and raw quering power of query languages like SQL with the familiarity, power, type-safety, and flexibility of the .NET Framework. LINQ comes in a couple different flavors (sadly, chocolate is not included):
As of the May CTP, LINQ can also be used to query DataSets ... but I haven't yet figured out a purpose for that, since the business objects that you get with SQLMetal, the OR/M code generator, are lighter weight, strongly-typed, and make heavy use of generics.
This blog entry wil introduce you to using LINQ with in-memory objects. The next blog entry will be about DLing, then I'll move on to XLinq after that.
Let's start with some simple in-memory data:
string[] names = {"Kevin", "Joe", "Bob", "Steve", "Al", "Rob", "Al", "DaVinci" };
In "legacy" C#, if you wanted to find all the names in this list that started with A, you'd have to write your own traversal. If you wanted to sort this array, you'd have to code your own custom IComparer function. There are a lot more things that people normally want to do against collections and lists that are, let's face it, a huge pain in the butt right now.
Not so with C# 3.0/LINQ. Take a look at this code:
var query = from name in names
orderby name descending
select name.ToLower();
foreach (string modifiedName in query)
{
Response.Write(modifiedName + "<br/>");
}
The keyword var here instructs the compiler to infer the data type (do not confuse this with weak or late-bound typing, as it is neither. The type will be inferred from the type of the data that is first stored in the variable). Then we have a LINQ expression (see the documentation in the May CTP available from Microsoft for all the syntax rules) that queries the array of names, sorts the names in descending order, and then converts all the names to lower-case in the process and finally outputs all of that to a Web page.
The other feature of C# 3.0/LINQ that should not be overlooked is the use of lambda functions. Having spent a lot of time in college with Scheme and LISP, I went positively giddy when I found this.
You can define a lambda function that can then be passed to any function that can accept them, such as the where clause of a query. For every SQL-style keyword in C#, there is also an equivalent language extension method (such as .Where()) that can be invoked in a more C#-style means, as shown below with a Lambda function:
Func<string, bool> filter = s => s.Length > 3;
string[] names = {"Kevin", "Joe", "Bob", "Steve", "Al", "Rob", "Al", "DaVinci" };
IEnumerable<string> expr =
from s in names .Where(filter)
orderby s select s.ToUpper();
foreach (string item in expr)
{
Response.Write(item + "<Br/>");
}
This code will output all names that contain more than three characters, and it will output them in uppercase.
LINQ even supports grouping, as shown below in this code that groups names by their length and displays how many words there are of each length. One of the biggest problems that I have with grouping operators in traditional SQL, especially in SQL Server, is that once I group the results, I no longer have access to the individual details that supported the grouping. Not so with LINQ:
var wordGroups = from word in names
group word by word.Length into g
select new { Length = g.Key, Words = g };
foreach (var wordGroup in wordGroups) foreach (var word in wordGroup.Words)
{
Response.Write("Words that have " + wordGroup.Length.ToString() + " Letters:<br/>");
{
Response.Write(" -" + word + "<Br/>");
}
}
This produces the following output:
Words that have 5 Letters:
-Kevin
-Steve
Words that have 3 Letters:
-Joe
-Bob
-Rob
Words that have 2 Letters:
-Al
-Al
Words that have 7 Letters:
-DaVinci
This is just the tip of the iceberg. Whether you're writing a huge business application or whether you're writing a little helper app - the ability to use LINQ to query in-memory structures is going to not only save us developers countless hours of wasted time iterating through garbage and creating temp tables and all other manner of hacks and kludges, it will make the code easier to read, easier to maintain, and its just plain cool!