1. Computing

LINQ to Objects

Collections, the LINQ Way

By

Updated March 11, 2012

Since it was introduced in VB.NET 2008, LINQ has become fundamental in VB.NET - but it's still widely misunderstood. This article is one of a series at About Visual Basic that covers the major ways to program LINQ. The goal is for a beginning Visual Basic .NET programmer to get up to speed on LINQ. If you found this article from a search and you would like to start at the beginning, you can find an introduction to the overall LINQ technology - what it covers and what you can do with it - in the article LINQ - An Example Driven Introduction with an example showing how LINQ could be used to start web pages using selections made with CheckBox controls. There is an index to all of the articles in the series in the beginning of the article.

When I first saw the name "LINQ to Objects", I thought, "Isn't everything in .NET an object? So doesn't this make it 'LINQ to Everything'?"

Ummmmm ... not quite. I strongly suspect that somebody in marketing had a hand in naming this member of the LINQ family of technologies because the name really doesn't make much sense. "LINQ to Objects" should probably have been named "LINQ to Collections" or something similar. According to Microsoft, "The term 'LINQ to Objects' refers to the use of LINQ queries with any IEnumerable or IEnumerable(Of T) collection directly, without the use of an intermediate LINQ provider or API."

This article, then, will demonstrate exactly what that means with some detailed explanations of examples. My goal is to provide much more detail than Microsoft does so that, even if you don't know LINQ from the 'missing link', you can follow these examples.

The place to start is with the easiest examples: an IEnumerable collection. (If you have questions about just what an IEnumerable interface is, I explain it all here: IEnumerable and IEnumerator Explained in Language You Understand.) Here's how to build one (with just a single element); in this case an ArrayList.


Public Class Booze
    Public Property BoozeFriendlyName As String
    Public Property CategoryName As String
    Public Property Recipes As String()
End Class
' ... then in a different class ...
Dim aBooze As New Booze With
    {
    .BoozeFriendlyName = "RotGut",
    .CategoryName = "Baaad Stuff",
    .Recipes =
        {
            "Death Wish",
            "No Tomorrow",
            "Zone Out"
        }
    }
Dim BoozeList As New ArrayList
BoozeList.Add(aBooze)

In this example, I just assigned values using a Dim statement. Most of the time, you get these values from a datastore such as a database or an XML file and one of the other LINQ technologies, such as LINQ to Entities, will be used. But LINQ to Objects can be used when your needs aren't quite as demanding.

Keep in mind that it's an instance of the object Booze that's added to the ArrayList, not the contents. Why is this important? Suppose you execute the code above and then change the values in aBooze and add it again.


aBooze.BoozeFriendlyName = "A Different Name"
aBooze.CategoryName = "A Different Category"
aBooze.Recipes = {"Recipe One", "Recipe Two"}
BoozeList.Add(aBooze)

Since you already added it earlier, you might expect that you would have two different elements in BoozeList. But you won't. The instance aBooze, which now has the second set of values in it, is just there twice.

--------
Click Here to display the illustration
--------

We still haven't seen the LINQ to Objects query, however. After you have an IEnumerable collection, the query is very SQL like. This returns two elements where CategoryName is "Baaad Stuff" from the ArrayList.


Dim query = From b As Booze In BoozeList
    Where b.CategoryName.StartsWith("B")
    Select b

There's a rich set of operators to work with in LINQ. For example, this statement also returns the two elements where CategoryName is "Baaad Stuff". The "*" character will match any character zero or more times.


Dim query = From b As Booze In BoozeList
    Where b.CategoryName Like "*aaa*"
    Select b

This isn't the full "regular expressions", but it's similar. Microsoft simply calls them "pattern options". If you're interested in using the much more powerful regular expressions syntax (see Regular Expressions in VB.NET for more), then you can do that too using the RegEx.IsMatch() method. This code produces the same two elements:


Dim myRegExString As New Regex(".*aaa.*")
Dim query = From b As Booze In BoozeList
    Where myRegExString.IsMatch(b.CategoryName)
    Select b

Notice that the match expression is slightly different from the "pattern option".

One source of IEnumerable collections that is often overlooked is the humble string. A string implements both the IEnumerable and the IEnumerable(Of T) interface so you can use LINQ to Objects on any string. The code below counts the number of "a" characters in the string "Baaad Stuff".


Dim theCount =
    Booze1.CategoryName.Count(Function(c) c = "a")
Console.WriteLine(theCount)

This can come in very handy when a method returns a string or a string array. For example, the GetFiles method of the Directory class returns an array containing the names of the files in a directory. You can query this just like any other string array. The example query below finds two file names that start with the characters "LINQ" (accomplished in the GetFiles method arguments) and ending in .exe in the current directory (in this case, the bin directory of the LINQtoObjectsEx project).


Dim root As String = "."
Dim dir As New System.IO.DirectoryInfo(root)
Dim fileList = dir.GetFiles(
    "LINQ*.*", IO.SearchOption.AllDirectories)
Dim query = From file In fileList
                Where file.Extension = ".exe"
                Order By file.Name
                Select file
Console.WriteLine(query.ElementAt(0).ToString)
Console.WriteLine(query.ElementAt(1).ToString)

Output:
LINQtoObjectsEx.exe
LINQtoObjectsEx.vshost.exe

--------
Click Here to display the illustration
--------

(This whole thing could also be done in the GetFiles method, but that wouldn't demonstrate the LINQ syntax!)

As you can tell, the real key to using LINQ to Objects is getting an IEnumerable collection. Once you have that, all kinds of options open up. As it turns out, "There's a LINQ for that."

The following code will query the DLL files of the .NET Framework and display a list of all of the methods that will work. This one displays a list from Microsoft.VisualBasic.dll, but some others include mscorlib.dll and System.Core.dll.


Imports System.Reflection
. . .
Dim asmbly As Assembly =
    Assembly.Load(
        "Microsoft.VisualBasic, " &
        "Version=4.0.30319.1, Culture=neutral, " &
        "PublicKeyToken=b03f5f7f11d50a3a")

Dim query = From type In asmbly.GetTypes()
                    Where type.IsPublic
                    From method In type.GetMethods()
                    Where method.ReturnType.IsArray = True
                    Let name = method.ToString()
                    Let typeName = type.ToString()
                    Group name
                    By typeName Into methodNames = Group
lstCollections.Items.Add(
    "Microsoft.VisualBasic.dll IEnumerable Methods")
For Each item In query
    lstCollections.Items.Add(item.methodNames)
    For Each theType In item.methodNames
        lstCollections.Items.Add("---" & theType)
    Next
Next

--------
Click Here to display the illustration
--------

You can get the Version and PublicKeyToken using the "strong name" Framework utility, sn.exe. An article explaining it can be found at Framework Tools - SN. Using the Visual Studio Command Prompt utility (remember to run it as Administrator), the command (for Microsoft.VisualBasic) is:


sn -T Microsoft.VisualBasic.dll

The output (for Framework 4.0) is:


Microsoft (R) .NET Framework Strong Name Utility  Version 4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Public key token is b03f5f7f11d50a3a
  1. About.com
  2. Computing
  3. Visual Basic
  4. Using VB.NET
  5. LINQ for VB.NET
  6. LINQ to Objects - Collections, the LINQ Way

©2014 About.com. All rights reserved.