To read the article online, visit http://www.4GuysFromRolla.com/articles/031109-1.aspx

An Extensive Examination of LINQ: Lambda Expressions and Anonymous Types

By Scott Mitchell


Introduction


The previous installment in this article series, Extension Methods, Implicitly Typed Variables, and Object Initializers, examined three new features to the C# 3.0 and Visual Basic 9 languages that allow for developers to use LINQ's standard query operators and providers to write SQL-like query syntax to work with common data stores. But extension methods, implicitly typed variables, and object initializers are only part of the story. Two additional language features - lambda expressions and anonymous types - are also essential ingredients in LINQ's unique syntax.

Recall that LINQ's standard query operators can work with any collection of data that implements the IEnumerable<T> interface. Some of the standard query operators perform rather straightforward operations on the collection; the Count standard query operator, for instance, simply returns the number of elements in the collection. However, other standard query operators are more flexible, allowing the page developer to dictate how the operator will work. The Where standard query operator is such an example - it filters the elements in the collection based on a developer-specified filtering method. But just how can a developer "pass" a method to the Where standard query operator as an input parameter? The .NET Framework has long supported the notion of delegates, which are type-safe function pointers. However, the syntax for delegates is a little confusing and verbose. Lambda expressions offer a much more terse syntax for defining an anonymous method.

Anonymous types allow for inline types. In a nutshell, anonymous types let you clump a set of values together into a new type without having to first declare the type via a class. For example, imagine that you have a collection of Employee objects, where each Employee object has properties like Name, Salary, HireDate, and so on. You may want to apply some filtering condition on this collection using the Where standard query operator and then project the collection of Employee objects into a collection of objects that includes just the Name and Salary properties. With anonymous types this style of projection is straightforward and natural. Without anonymous types you would first have to create a class like EmployeeSimplified that contained only those two properties of interest.

This article provides an overview of lambda expressions and anonymous types. These two language enhancements, along with extension methods, implicitly typed variables, and object initializers, are what allows for LINQ's query syntax. Read on to learn more!

Working with Methods


Methods can be though of as a black boxes that takes in some input and performs some action based on the supplied inputs. Usually, the inputs supplied to a method consist of simple types (integers, Booleans, strings), objects, or collections of objects, but it is possible to create a method that accepts another method as one of its inputs. This is most useful for framework designers who are building a library that will be used by multitudes of different developers in a variety of ways.

Consider the .NET Framework's generic collection classes, such a List<T>, which are designed to hold a strongly-typed collection of objects. The objects that makeup the collection are defined by the developer using the class. For example, a developer can use the List<T> class to hold a collection of integers, or a collection of strings, or a collection of Employee objects. The List<T> class has a Sort method that will sort the items in the list, but this begs the question: How can the List<T> possibly sort its contents when it doesn't even know what type of data it will hold? Moreover, how can a List determine how to sort a collection of Employee objects? Do you sort by the values in the Name property? By the Salary property? By some other mechanism?

The answer is that the List<T> class cannot know how to implement the Sort method. Instead, it requires that the developer using the class provide this functionality. In short, the developer using the List<T> class's Sort method must first create a method that implements the sorting logic - i.e., given two objects of the type stored in the List<T>, the method determines which one comes before the other. This method must then be passed into the List<T> class's Sort method, which uses it to sort its data.

In order to pass a method as an input parameter into another method there needs to be a mechanism by which a method's signature - it's input parameters and their types and its return value - can be defined as a type, along with a way that a particular method "instance" can be referenced like a variable. The .NET Framework offers this mechanism through delegates.

A delegate allows you to define a method signature as a type. For example, the following delegate named ShouldFireEmployee defines a method type that takes an object of type Employee as an input parameter and returns an Boolean value:

// C# - define a delegate
public delegate bool ShouldFireEmployee(Employee emp);


' VB - define a delegate
Public Delegate Function ShouldFireEmployee(ByVal emp As Employee) As Boolean

Once defined, the delegate can be referenced like a type.

Now imagine that we wanted to create a method that would "fire" employees, but we want the developer calling this method to supply the method that determines whether or not an individual employee should be fired. We could write the following code:

// C#
public void FireEmployees(List<Employee> emps, ShouldFireEmployee shouldFire)
{
   foreach(Employee emp in emps)
      if (shouldFire(emp) == true)
         emp.Fire();
}


' VB
Public Sub FireEmployees(ByVal emps As List(Of Employee), ByVal shouldFire As ShouldFireEmployee)
   For Each emp As Employee in emps
      If shouldFire(emp) = True Then
         emp.Fire()
      End If
   Next
End Sub

Note that the FireEmployees method's second input parameter is the ShouldFireEmployee delegate. The shouldFire variable is a reference to a method that has the defined signature (accepts an Employee as input and returns a Boolean) and can be called just like you would normally call a function.

Before the FireEmployees method could be called the developer would need to first define the method. It could then be passed in as a delegate instance. The following code demonstrates this:

// C# - first create a method that conforms to the ShouldFireEmployee delegate signature
public bool NeedToGo(Employee emp)
{
   return emp.Salary > 150000M;
}


...

// Create an instance of the delegate
ShouldFireEmployee myDelegate = new ShouldFireEmployee(NeedToGo);

// Now call the FireEmployees method, passing in myDelegate, which is a "pointer" to the NeedToGo method
FireEmployees(listOfEmployees, myDelegate);


'VB - first create a method that conforms to the ShouldFireEmployee delegate signature
Public Function NeedToGo(ByVal emp As Employee) As Boolean
   Return emp.Salary > 150000
End Function


...

' Call the FireEmployees method, passing in the address of the NeedToGo method
FireEmployees(listOfEmployees, AddressOf NeedToGo)

Note that the C# and VB syntax for creating a delegate and passing it in varies slightly, but the overarching concept is the same. For more on using delegates in C# see Delegates and Events in C#; for an overview of delegates in Visual Basic, see Delegates in Visual Basic .NET.

Moving Forward: Anonymous Methods and Delegates


One of the pain points of using delegates is that the method the delegate references must be defined like any other method. In the example above, we had to create the NeedToGo method as a regular, stand-alone method so that it could be passed into the FireEmployees. If this method was only going to be used in one spot - namely, in this one call to FireEmployees - it seems a waste to have to create a stand-alone method. It's not only an eyesore, but also could potentially be called from elsewhere in our code.

C# 2.0 - the version released with Visual Studio 2005 - added the concept of anonymous methods. (Unfortunately, Visual Basic 8 did not include support for anonymous methods.) In short, with anonymous methods we can define the method body inline like so:

// C#
FireEmployees(listOfEmployees, delegate(Employee emp) { return emp.Salary > 150000M; });

Anonymous delegates offer a more terse syntax for defining a one-off method.

And Now, Lambda Expressions


Lambda expressions - supported in both C# 3.0 and Visual Basic 9 - offer an even more concise syntax for defining an anonymous method. In C#, lambda expressions can accept one or more input parameters and either evaluate a single expression or execute a statement block. Lambda expression are denoted by the lambda operator in C# (=>). The input parameter(s) appear to the left of =>, while the expression or statement block appears to the right. One of the hallmarks of lambda expressions is that they do not need to type the input parameters. Additionally, when using an expression lambda you do not need to specify the return keyword.

In general, a lambda expression in C# can take one of the following forms:

// C# lambda expression syntax
single input parameter => expression<br />
single input parameter => { statements }<br />
(comma-delimited list of input parameters) => expression<br />
(comma-delimited list of input parameters) => { statements }<br />

Returning to our FireEmployees example, we could use a lambda expression to pass in the method to execute to determine which employee to fire:

// C#
FireEmployees(listOfEmployees, emp => emp.Salary > 150000M);

The lambda expression starts by defining the input parameter name (emp in this case, although it could be named anything), followed by the lambda operator (=>). The expression appears to the right of => and returns a Boolean value: True if emp.Salary is greater than 150,000, False otherwise.

In C#, lambda expressions can alternatively include statement blocks to the right of the lambda operator. For example, if the calculation of whether to fire the employee was more complex and couldn't be boiled down into a single expression, we could use the following syntax:

// C#
FireEmployees(listOfEmployees, emp => { statement1; statement2; ...; return BooleanValue; });

If the ShouldFireEmployee delegate accepted two or more input parameters the lambda expression syntax would need to be updated to the following:

// C#
FireEmployees(listOfEmployees, (inputParam1, inputParam2, ...) => ...);

Lambda expressions in Visual Basic have a different syntax than C#, as there's no lambda operator in VB. Furthermore, you cannot use statement blocks in VB's lambda expressions; instead, it can only return an expression. Lambda expressions in VB use the Function keyword like so:

' VB
Function(input parameters) expression

We could update the FireEmployees example by using a lambda expression instead of explicitly defining the NeedToGo method like so:

// VB
FireEmployees(listOfEmployees, Function(emp) emp.Salary > 150000)

Note that like in the C# syntax we do not need to define the type of the input parameter(s); nor do we need to include the Return keyword.

At first, lambda expressions look a bit like gobbledygook. It takes a while for your brain and fingers to grok this new syntax, but keep in mind that lambda expressions are just another way of writing a method. The core pieces of a method are there - the input parameters and the body - but they're just jumbled up differently. With sufficient practice the lambda expression syntax will quickly become second nature.

Lambda Expressions in LINQ's Standard Query Operators


A number of LINQ's standard query operators include a delegate as an input parameter. The Where operator is one such example, which filters a collection based on a supplied delegate. Lambda expressions are ideal for calling these standard query operators. We saw such an example in the An Introduction To LINQ article. Namely, the demo included an array of integers and then computed the average value of the odd numbers. The Where standard query operator was used to retrieve the odd values from the list using a lambda expression:

// C#: Get the average of the odd Fibonacci numbers in the series...
int[] fibNum = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
double averageValue = fibNum.Where(num => num % 2 == 1).Average();


'VB: Get the average of the odd Fibonacci numbers in the series...
Dim fibNum() As Integer = {1, 1, 2, 3, 5, 8, 13, 21, 34}
Dim averageValue As Double = fibNum.Where(Function(num) num Mod 2 = 1).Average()

The Where operator expects a delegate that accepts a single object as input (namely an object of type T, where T is the type of objects in the collection being operated on) and returns a Boolean value. Therefore, our lambda expression defines a single input parameter (num, in the above example) and an expression that returns a Boolean value. In the snippet above, the expression returns True if the remainder of num / 2 is 1 (in other words, if num is odd) and false otherwise.

The download available at the end of this article shows how to use lambda expressions against the List<T> class's Sort method.

Syntactic Sugar, Anyone?
Like with the extension methods, implicitly typed variables, and object initializers language features examined in the previous installment, lambda expressions are syntactic sugar. The lambda expression syntax in your C# or Visual Basic code gets converted into an explicit method by the compiler and the lambda expression is replaced by a delegate reference.

Anonymous Types


When you want to define a type you typically do so via a class. For example, the download available at the end of this article has an Employee class that defines the properties and methods of the type. With that class defined, I can create and use Employee objects from any ASP.NET page in my website, or from other classes in my project. The steps of creating a class and defining its members is a relatively easy task, but can be overkill if you have need for a type that will be used in one place only and no where else. For example, on a particular page I may want to first filter a collection of Employee objects and then only work with the Name and Salary properties. But doing so would entail creating a new class, perhaps named EmployeeSimplified, that contained just these two properties. Seems like a lot of work.

C# 3.0 and Visual Basic 9 offer another option - anonymous types. An anonymous type is a type that is defined via inline code and does not require a formal class definition. For example, the following snippet of code creates a new object that has two properties, Name and Salary, with values "Scott" and 50,000, respectively.

// C#
var EmployeeOfTheMonth = new { Name = "Scott", Salary = 50000M };


' VB
Dim EmployeeOfTheMonth = New With {.Name = "Scott", .Salary = 50000}

The name of the new object is EmployeeOfTheMonth. Its type, however, is not explicitly defined anywhere. Instead, it is anonymously defined via the object initializer syntax. Here EmployeeOfTheMonth is an implicitly typed variable. (For more on object initializers and implicitly typed variables refer back to Extension Methods, Implicitly Typed Variables, and Object Initializers.)

The EmployeeOfTheMonth object is strongly-typed; we get full-blown IntelliSense support.

Visual Studio provides full IntelliSense support for anonymous types.

Anonymous Types and LINQ


LINQ offers two projection standard query operators: Select and SelectMany. A projection operator is one that takes the original object type and creates a new type with specified properties. The syntax used by these projection operators is quite concise thanks to anonymous types.

The following snippet shows LINQ's Select operator in action. We start with a collection of Employee objects and then filter it using a Where clause so that only employees who make more than $50,000 are considered. Next, the Select operator is used to create a new anonymous type that contains two properties named Name and Compensation, whose values are populated from the Name and Salary properties of each Employee object.

// C# - Create a list of EmployeeCS objects
List<EmployeeCS> Workers = new List<EmployeeCS>() {
      new EmployeeCS() { EmployeeID = 1, Name = "Scott", Salary = 50000M },
      new EmployeeCS() { EmployeeID = 2, Name = "Jisun", Salary = 150000M },
      new EmployeeCS() { EmployeeID = 3, Name = "Alice", Salary = 33000M },
      new EmployeeCS() { EmployeeID = 4, Name = "Sam", Salary = 75000M },
      new EmployeeCS() { EmployeeID = 5, Name = "Dave", Salary = 85000M },
      new EmployeeCS() { EmployeeID = 6, Name = "Marie", Salary = 53000M }
};

var TopWorkers = Workers.Where(emp => emp.Salary > 50000M);
var SimplifiedTopWorkers = TopWorkers.Select(emp => new { Name = emp.Name, Compensation = emp.Salary });


' VB - Create a list of EmployeeCS objects
Dim Workers As New List(Of EmployeeVB)
Workers.Add(New EmployeeVB With {.EmployeeID = 1, .Name = "Scott", .Salary = 50000})
Workers.Add(New EmployeeVB With {.EmployeeID = 2, .Name = "Jisun", .Salary = 150000})
Workers.Add(New EmployeeVB With {.EmployeeID = 3, .Name = "Alice", .Salary = 33000})
Workers.Add(New EmployeeVB With {.EmployeeID = 4, .Name = "Sam", .Salary = 75000})
Workers.Add(New EmployeeVB With {.EmployeeID = 5, .Name = "Dave", .Salary = 85000})
Workers.Add(New EmployeeVB With {.EmployeeID = 6, .Name = "Marie", .Salary = 53000})

'Get back a list of Workers who make more than $50,000, projecting the results
'onto an anonymous type with two properties: Name and Compensation
Dim TopWorkers = Workers.Where(Function(emp) emp.Salary > 50000)
Dim SimplifiedTopWorkers = TopWorkers.Select(Function(emp) New With {.Name = emp.Name, .Compensation = emp.Salary})

As you can see, the Select operator takes the current type (List<Employees>, in this case) and is passed a method that projects the current type into a new type. This method is specified by a lambda expression in the above example. Specifically, the lambda expression takes an Employee object (emp) as input and then uses the anonymous type syntax to create a new type with properties Name and Compensation whose values are assigned the values of emp.Name and emp.Salary, respectively. In short, the Select operator is enumerating each Employee object in TopWorkers and for each one it's calling the passed-in method, which generates a new object with an anonymous type whose two properties are assigned values from the current Employee object.

More Syntactic Sugar
Like with lambda expressions, anonymous types are syntactic sugar. The anonymous type syntax in your C# or Visual Basic code gets converted into an explicit types by the compiler.

Conclusion


LINQ's SQL-like query syntax is possible due to a number of enhancements to the C# and Visual Basic programming languages. In this installment and the previous one, we explored each of these essential language enhancements. Now that we have the underpinnings of the language enhancements down, we're ready to turn our attention to a more detailed look at LINQ's standard query operators. Following that, we'll explore LINQ's query syntax!

Happy Programming!

  • By Scott Mitchell


    Attachments:


  • Download the code associated with this article series
  • Further Reading


  • An Introduction to Delegates
  • Delegates and Events in C# (Delegates in Visual Basic .NET)
  • Anonymous Methods (C# Programming Guide)
  • New Language Feature: Lambda Expressions
  • Lambda Expressions in Visual Basic
  • New Language Feature: Anonymous Types
  • Article Information
    Article Title: ASP.NET.An Extensive Examination of LINQ: Lambda Expressions and Anonymous Types
    Article Author: Scott Mitchell
    Published Date: March 11, 2009
    Article URL: http://www.4GuysFromRolla.com/articles/031109-1.aspx


    Copyright 2014 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers