Introducing LINQ for Visual Basic

C# 3.0 incorporates LINQ (Language INtegrated Query), a cool technology that adds dynamic queries to all kinds of objects in a familiar SQL-like style. LINQ code looks like embedded SQL statements, which I actually don't care for because SQL has never looked pretty to me. I also do not believe that LINQ adds clarity to code. It looks terse and somewhat ambiguous. In a nutshell, LINQ is a sexy technology (as they are fond of saying in Redmond), but it is not pretty.

This article shows you how to get LINQ for Visual Basic and begin using it now. As you read, you can begin formulating your own opinion of its elegance and usefulness.

Using LINQ for VB Now

Begin by downloading and installing LINQ. This article uses the May 2006 CTP (Community Technology Preview).

Tip: If you like bleeding-edge technologies and want to know what Microsoft is working on for future products, check out research.microsoft.com. LINQ, for example, came out of the Omega research project.

As with all pre-release software, you download and install with some risk. In this case, LINQ will cause minor problems with IntelliSense and CodeRush. If you rely on CodeRush, Refactor, and IntelliSense, then install LINQ on a Virtual PC instance with Visual Studio 2005 on it.

Working with the LINQ CTP

Once you have downloaded and installed LINQ, you will notice a new folder named C:\Program Files\LINQ Preview. This folder contains LINQ documentation, assemblies, and examples. When you run Visual Studio after installing LINQ, you will get a message indicating LINQ for C# is installed, but LINQ for VB also will be installed.

To use LINQ and create a project, pick one of the LINQ project templates as shown in Figure 1. These project templates will add the appropriate references to LINQ assemblies and any necessary import statements.

Figure 1: LINQ Project Templates

All of the samples in this article are part of a console application, and the referenced assemblies—including Microsoft.VisualBasic.LINQ, System.Data.DLinq, and System.Xml.XLinq—will be added to your project's list of references (see Figure 2). In fact, LINQ is supported for ADO and XML too.

Figure 2: References to Essential LINQ Assemblies

Tip: To view the references in a VB project, click the Show all files button (highlighted in blue in Figure 2) in the Solution Explorer.

Having installed LINQ, let's look at some of the things you can do with this technology.

Using LINQ

LINQ is a query language for .NET—VB in the examples to follows. To be useful and intuitive, I would expect LINQ to do almost everything SQL can do. Although I didn't test its limits, LINQ proved pretty intuitive as I developed the examples. I literally guessed at them based on what I anticipated from a query language. The following sections discuss some of the queries you can write with LINQ.

Selecting Numbers from an Array

LINQ for VB looks a little like reverse polish notation for SQL. For example, you can define an array of integers and then query that array using a WHERE predicate to return a subset of integers from an unordered set. Listing 1 shows a VB subroutine that does just that with a subset of fewer than 10 integers.

Listing 1: Select Numbers from an Array of Unordered Integers Using LINQ

Sub SampleOne()
  Dim numbers = {2, 1, 34, 5, 8, 13, 21, 33}
 
  Dim lessThanTen = From num In numbers _
    Where num < 10 _
    Select num
 
  For Each Dim n In lessThanTen
    Console.WriteLine(n)
  Next
 
  Console.ReadLine()
 
End Sub

This example defines an array of random integers. The LINQ query (shown in bold) defines an anonymous type lessThanTen, which becomes an instance of IEnumerable. (Anonymous types are much more spectacular to C# programmers; you VB programmers are used to this type of notation.) The LINQ query From num in numbers Where num < 10 Select Num initializes lessThanTen. And, of course, most of us know by now that any IEnumerable type can be used in a For Each statement. The result from Listing 1 are the numbers 1, 2, 5, and 8 printed to the console.

Notice that numbers uses an array initializer without explicitly declaring numbers as an array (using numbers()). The variable numbers's type is an anonymous type whose actual type is inferred. The same is true of the anonymous variable n. (Note the unusual location of the keyword Dim in the For Each statement. This is valid .NET 3.0 code.)

Introducing LINQ for Visual Basic

Using LINQ

LINQ is a query language for .NET—VB in the examples to follows. To be useful and intuitive, I would expect LINQ to do almost everything SQL can do. Although I didn't test its limits, LINQ proved pretty intuitive as I developed the examples. I literally guessed at them based on what I anticipated from a query language. The following sections discuss some of the queries you can write with LINQ.

Selecting Numbers from an Array

LINQ for VB looks a little like reverse polish notation for SQL. For example, you can define an array of integers and then query that array using a WHERE predicate to return a subset of integers from an unordered set. Listing 1 shows a VB subroutine that does just that with a subset of fewer than 10 integers.

Listing 1: Select Numbers from an Array of Unordered Integers Using LINQ

Sub SampleOne()
  Dim numbers = {2, 1, 34, 5, 8, 13, 21, 33}
 
  Dim lessThanTen = From num In numbers _
    Where num < 10 _
    Select num
 
  For Each Dim n In lessThanTen
    Console.WriteLine(n)
  Next
 
  Console.ReadLine()
 
End Sub

This exampe defines an array of random integers. The LINQ query (shown in bold) defines an anonymous type lessThanTen, which becomes an instance of IEnumerable. (Anonymous types are much more spectacular to C# programmers; you VB programmers are used to this type of notation.) The LINQ query From num in numbers Where num < 10 Select Num initializes lessThanTen. And, of course, most of us know by now that any IEnumerable type can be used in a For Each statement. The result from Listing 1 are the numbers 1, 2, 5, and 8 printed to the console.

Notice that numbers uses an array initializer without explicitly declaring numbers as an array (using numbers()). The variable numbers's type is an anonymous type whose actual type is inferred. The same is true of the anonymous variable n. (Note the unusual location of the keyword Dim in the For Each statement. This is valid .NET 3.0 code.)

Using Ordering Clauses in LINQ

Listing 2 defines an unordered array of Fibonacci numbers and uses an ORDER clause to order the array. (Google Fibonacci for a definition. You will find these numbers pretty interesting.)

Listing 2: Ordering an Array of Integers Using LINQ

Sub SampleTwo()
  Dim numbers = {2, 1, 34, 5, 8, 13, 21, 3}
 
  Dim ordered = From num In numbers _
   Select num _
   Order By num
 
  For Each Dim n In ordered
    Console.WriteLine(n)
  Next
 
  Console.ReadLine()
 
End Sub

Listing 2 is like Listing 1 but with the addition of the Order By clause. The anonymous type ordered contains the re-ordered list of integers: 1, 2, 3, 5, 8, 13, 21, 34. Adding the keyword Descending after the clause Order By num will sort the list in reverse order. This variant is shown in Listing 3.

Listing 3: Sorting in Reverse Order

Sub SampleThree()
  Dim numbers = {2, 1, 34, 5, 8, 13, 21, 33}
 
  Dim ordered = From num In numbers _
    Select num _
    Order By num Descending
 
  For Each Dim n In ordered
    Console.WriteLine(n)
  Next
 
  Console.ReadLine()
End Sub

Sorting Generic Lists of Custom Types

You can also apply LINQ to custom types. Suppose I define a custom type Customer (see Listing 4) and want to sort a generic list of customers.

Listing 4: A User-Defined Customer Class

Public Class Customer

    Private fid As Integer
    Private fname As String
    Private fcity As String

    Public Sub New(ByVal id As Integer, ByVal name As String, _
    ByVal city As String)
        fid = id
        fname = name
        fcity = city
    End Sub

    Public Overrides Function toString() As String
        Dim mask As String = "{0} is in {1}"
        Return String.Format(mask, fname, fcity)
    End Function


    Public Property ID() As Integer
        Get
            Return fid
        End Get
        Set(ByVal value As Integer)
            fid = value
        End Set
    End Property

    Public Property Name() As String
        Get
            Return fname
        End Get
        Set(ByVal value As String)
            fname = value
        End Set
    End Property

    Public Property city() As String
        Get
            Return fcity
        End Get
        Set(ByVal value As String)
            fcity = value
        End Set
    End Property

End Class

I can define the Customer class and instantiate a List(Of T) where T is a customer using a specific field from the class Customer (see Listing 5).

Listing 5: Initializing a Generic List of Customer Objects and Sorting Based on the City Field

Sub SampleFour()
 
  Dim customers = New List(Of Customer)
  customers.Add(New Customer(1, "Kimmel Computers", "Plattsburgh"))
  customers.Add(New Customer(2, "Fred's Frieds", "Memphis"))
  customers.Add(New Customer(3, "House of Clams", "Detroit"))
 
  Dim ordered = From cust In customers _
    Select cust _
    Order By cust.City
 
  For Each Dim c In ordered
    Console.WriteLine(c.toString())
  Next
 
  Console.ReadLine()
 
End Sub

Implementing IComparable

If you modify Customer by implementing Icomparable, you can tell Customer objects how to compare themselves. Implement IComparable by adding the Implements IComparable statement to the Custom class and adding the Function CompareTo. Listing 6 shows the revised Customer class, and Listing 7 shows the revised code from Listing 5 that now uses LINQ to sort based on the implementation of IComparable.

Listing 6: Implement IComparable to Compare Customer Objects by City

Public Class Customer
    Implements IComparable

    Private fid As Integer
    Private fname As String
    Private fcity As String

    Public Sub New(ByVal id As Integer, ByVal name As String, _
    ByVal city As String)
        fid = id
        fname = name
        fcity = city
    End Sub

    Public Overrides Function toString() As String
        Dim mask As String = "{0} is in {1}"
        Return String.Format(mask, fname, fcity)
    End Function


    Public Property ID() As Integer
        Get
            Return fid
        End Get
        Set(ByVal value As Integer)
            fid = value
        End Set
    End Property

    Public Property Name() As String
        Get
            Return fname
        End Get
        Set(ByVal value As String)
            fname = value
        End Set
    End Property

    Public Property city() As String
        Get
            Return fcity
        End Get
        Set(ByVal value As String)
            fcity = value
        End Set
    End Property

    Public Function CompareTo(ByVal obj As Object) _
        As Integer Implements System.IComparable.CompareTo
        Return city.CompareTo(obj.City)
    End Function
End Class

Listing 7: Sorting a Generic List of IComparable Customer Objects

Sub SampleFive()
  Dim customers = New List(Of Customer)
  customers.Add(New Customer(1, "Kimmel Computers", "Plattsburgh"))
  customers.Add(New Customer(2, "Fred's Frieds", "Memphis"))
  customers.Add(New Customer(3, "House of Clams", "Detroit"))
 
  Dim ordered = From cust In customers _
    Select cust _
    Order By cust
 
  For Each Dim c In ordered
    Console.WriteLine(c.toString())
  Next
 
  Console.ReadLine()
End Sub

The only difference between Listing 7 and Listing 5 is that the Order By clause now specifies that you are sorting only Customer objects. The sort field is implicit as defined by the CompareTo function.

A SQL-Like Query Language

This article introduced LINQ and demonstrated how you can combine this technology with existing technologies such as interfaces and generic lists to support a SQL-like query language in your VB.NET code. Of course, LINQ (and .NET 3.5) introduce many more capabilities, including anonymous types and support for ADO.NET and XML. Go ahead and explore.

About the Author

Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming, including Visual Basic .NET Power Coding (Addison-Wesley) and UML Demystified (McGraw-Hill/Osborne). He is the president and co-founder of the Greater Lansing Area Users Group for .NET (www.glugnet.org) and a Microsoft Visual Developer MVP.

Copyright © 2006 by Paul T. Kimmel. All Rights Reserved.



Comments

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

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: May 7, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT This eSeminar will explore three popular games engines and how they empower developers to create exciting, graphically rich, and high-performance games for Android® on Intel® Architecture. Join us for a deep dive as experts describe the features, tools, and common challenges using Marmalade, App Game Kit, and Havok game engines, as well as a discussion of the pros and cons of each engine and how they fit into your development …

  • Instead of only managing projects organizations do need to manage value! "Doing the right things" and "doing things right" are the essential ingredients for successful software and systems delivery. Unfortunately, with distributed delivery spanning multiple disciplines, geographies and time zones, many organizations struggle with teams working in silos, broken lines of communication, lack of collaboration, inadequate traceability, and poor project visibility. This often results in organizations "doing the …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds