Using Where Clauses with LINQ in VB
Introduction
I have a good understanding of XML, but don't use XPath that often. I can command write queries against Active Directory, but have to look up the syntax because I do it infrequently. I have been using SQL in its various forms for more than a decade, so writing SQL queries, except in a few cases is something I can do adroitly. And, when it comes to querying objects in code I have the most experience, having re-written dozens of algorithms long before they were part of the framework. All of these conflicting skill sets represent part of the problem: programming today has up until now required too many disparate skill sets. Having to focus on how to accomplish something and not just expressing a solution makes querying data much harder than it should be. Enter LINQ.
Only a few times in the past--when I did a stint with Microsoft Consulting--have I been part of the internal discussions for Microsoft technologies, discussions about the motivation behind creating a new technology. Unfortunately, besides from very helpful discussions with people like Tim Ng and Charlie Calvert, I wasn't privy to the early discussions about LINQ. One can make a reasonable guess though-too many ways to query data, too many skill sets, and too much inconsistency. LINQ was invented to make it easier to express what you want to accomplish and less on how or the underlying technology.
The result is LINQ. LINQ in its simplest form is
basically very similar to an inverted SQL query--with select
coming last--but there are several intricacies that it is
helpful to know about. In this article I am focusing on the
WHERE clause, including how it evolved and how
you can apply it in LINQ queries.
Understanding the Origins of the Where Clause
Interfaces like IEnumerable and IEnumerable(Of T) are sealed interfaces, and generally interfaces aren't suppose to change because any change would be a breaking change. As a solution extension methods were invented (or introduced into .NET). There are some 1,000 programming languages, so extension methods may have been introduced in some earlier language like Modula-2, LOOPS, Flavors, or SmallTalk but .NET was where I first heard about them.
An extension method is basically a static method in a static class. The first argument defines the type being extended and the compiler resolves an extension method as if it were a member--of the type being extended. Extension methods in a nutshell are a way to extend an existing type without actually modifying that type. Extension methods are compiler-resolution magic.
The method Where was originally introduced as an
extension method for types that implement IEnumerable(Of T),
such as a collection or array of something. The basic
Where extension method accepts a generic
delegate or Lambda Expression--a short hand form of the
delegate--with a generic input and a Boolean result. The
second form accepts the input type, an integer representing
the items index, and a Boolean. These can be expressed as an
instance of the generic delegate Func(Of T, Boolean) or
Func(Of T, Integer, Boolean). Listing 1 demonstrates the
Where extension method using the generic delegate Func(Of T,
Boolean).
Sub Listing1()
Dim numbers() As Integer = {1, 2, 3, 4, 5}
Dim test As Func(Of Integer, Boolean) = _
Function(i As Integer) i Mod 2 = 1
Dim odds = numbers.Where(test)
For Each num In odds
Console.WriteLine(num)
Next
Console.ReadLine()
End Sub
Listing 1: Using the Where extension method with the generic delegate Func(Of T, Boolean).
In the example an array of integers is defined. Next, the
generic delegate Func (Of Integer, Boolean) is assigned the
Lambda expression Function (I as Integer) I Mod 2 = 1
followed by the Where extension method called
on the array and the output sent to the console. It is worth
noting that the Lambda expression could be used directly in
the Where method (as shown in Listing 2).
Sub Listing2()
Dim numbers() As Integer = {1, 2, 3, 4, 5}
Dim odds = numbers.Where(Function(i As Integer) i Mod 2 = 1)
For Each num In odds
Console.WriteLine(num)
Next
Console.ReadLine()
End Sub
Listing 2: Code that behaves identically to Listing 1 with the Lambda expression used directly in the Where method.
Lambda expressions are simply short hand function
notation, used for convenience in places like
Where extension methods. For more on Lambda
expressions see my book LINQ Unleashed for C# or
Professional DevExpress ASP.NET Controls. Both books have
several examples of LINQ expressions and a discussion of
Lambda expressions (Both books are in C#; while the syntax
is different the concepts are the same).
Using Where with a Single Predicate
In LINQ the Where clause uses a syntax
similar to a SQL statement. When you write a
Where clause in LINQ the compiler converts it
to a Where extension method call. The argument
or arguments to a Where clause have to evaluate
to a Boolean expression and can be referred to as predicates
or expressions (I will use either expression, based on which
sounds the best in a particular sentence).
Where clauses can have a single predicate, multiple
predicates formulated with a combination of And
or Or operators, or multiple Where
clauses. Listing 3 is a revision of Listing 2. Listing 3
converts the direct use of the Where extension
method with its implicit use in a LINQ query.
Sub Listing3()
Dim numbers() As Integer = {1, 2, 3, 4, 5}
Dim odds = From number In numbers _
Where number Mod 2 = 1 _
Select number
For Each num In odds
Console.WriteLine(num)
Next
Console.ReadLine()
End Sub
Listing 3: A LINQ query that obtains the odd numbered integers.
In the example, the Where clause has a
single predicate-number Mod 2 = 1. When the value in the
query is odd it ends up in the result set.
I don't have a crystal ball, but I can guess what you
might be thinking: numbers. Where is a lot
shorter and simper than the LINQ query shown in Listing 3.
In this instance you would be correct. The difficulty in
writing lengthy queries using all extension methods is that
the results become very challenging to read and write the
more complex the queries get. Use LINQ and let the compiler
code-generate the extension method calls.

Comments
There are no comments yet. Be the first to comment!