Understanding the Role of Lambda Expressions

C# and VB now support the construction of ‘lambda expressions’. Simply put, lambda expressions are used
to simplify working with delegate types. By and large, any delegate object can be substituted with a proper
lambda expression (VB does have more restrictions, which are examined later). The compiler will infer the
appropriate delegate at compile time.

For example, if a method requires a new delegate object as a parameter, you can pass a lambda expression
instead. The end result is typically a cleaner, more functional, code base. Lambdas can reduce the amount of
code you need to author by hand. To this end, lambdas are always entirely optional and nothing more than
syntactic sugar.

C# lambdas are created using the new lambda operator (=>). VB lambdas are defined by making use of the

Function
statement.

Although C# and VB lambdas are both used to simplify interaction with delegate types, C# and VB handle
them quite differently. As of .NET 3.5, C# lambdas are a tad more flexible than VB lambdas. However, for
most situations, either language will allow you to build useful lambda expressions.

A First Look at Lambda Expressions
To understand the usefulness of lambda expressions, consider the .NET generic Predicate<T> delegate type.
This delegate can ‘point to’ any method that returns a
Boolean and takes a single type parameter as input.
This particular delegate can be useful when you need to determine the truth or falsity of a variable based on a
mathematical statement.

The List<T>.FindAll() method requires an instance of Predicate<T> as a parameter. Using the
Predicate<T>
delegate and the List<T>.FindAll() method, you could build a program that finds all even numbers in a list of
integers. Here is the program in question, using traditional C# delegate syntax. The output will display the
numbers 20, 4, 8 and 44.


// C#
class Program
{
 static void Main(string[] args)
 {
   // Fill a list using C# 3.0 collection init syntax.
   List<int> list = new List<int>() {20, 1, 4, 8, 9, 44};   

   // Create a Predicate<T> object for use by the List<T>.FindAll()
   // method.
   Predicate<int> callback = new Predicate<int>(IsNumberEven);

   // Call FindAll(), passing the delegate object.
   List<int> evenNumbers = list.FindAll(callback);

   // Print out the result set.    
   Console.WriteLine("Here are the even numbers:");
   foreach (int evenNumber in evenNumbers)
   {
     Console.WriteLine(evenNumber);
   }
 }

 // Target for the Predicate<T> delegate.
 static bool IsNumberEven(int i)
 {
   // Is it an even number?
   return (i % 2) == 0;
 }
}

// Target for the Predicate<T> delegate.
static bool IsNumberEven(int i)
{
 // Is it an even number?
 return (i % 2) == 0;
}
}


The VB code is very similar. Recall, however, that VB does not allow collection initialization syntax. Thus,
List(Of T) is filled via a call to AddRange().


' VB
Option Strict On

Module Program
 Sub Main()
   Dim list = New List(Of Integer)()
   list.AddRange(New Integer() {20, 1, 4, 8, 9, 44})

   ' Create a Predicate<T> object for use by the List<T>.FindAll()
   ' method.
   Dim callback As New Predicate(Of Integer)(AddressOf IsNumberEven)

   ' Call FindAll(), passing the delegate object.
   Dim evenNumbers As List(Of Integer) = list.FindAll(callback)

   ' Print out the result set.    
   Console.WriteLine("Here are the even numbers:")
   For Each evenNumber As Integer In evenNumbers
     Console.WriteLine(evenNumber)
   Next
 End Sub

 ' Target for the Predicate(Of T) delegate.
 Function IsNumberEven(ByVal i As Integer) As Boolean
 
  ' Is it an even number?
   Return (i Mod 2) = 0
 End Function
End Module


One problem with traditional delegates is that they typically force you to build target methods (such as the
IsNumberEven() function), which are usually only called by the delegate itself. Under C# 2.0, anonymous
methods provide a somewhat cleaner alternative, given that you can ‘inline’ the delegate target. VB did not,
and does not, support anonymous methods (although use of the
Function statement is similar).

Thus, the previous C# code could be remodeled to use an anonymous method as follows. Notice that you no
longer need to have a separate target method for the Predicate<T> delegate. Also recall that C# anonymous
methods do not require specifying the type of the underlying delegate. You can simply use the
delegate
keyword. The compiler will infer the correct underlying delegate
(Predicate<T>).


static void Main(string[] args)
{
List<int> list = new List<int>() {20, 1, 4, 8, 9, 44};   

// Use an C# 2.0 anonymous method.
List<int> evenNumbers = list.FindAll(delegate(int i)
  { return (i % 2) == 0; } );

Console.WriteLine("Here are the even numbers:");
foreach (int evenNumber in evenNumbers)
{
  Console.WriteLine(evenNumber);
}
}


Although this C# example can be considered ‘better’, there are still some problems:
     •        You are still required to use the delegate keyword (or a strongly typed
Predicate<T>).
     •        The parameter list must be exact match.

Now consider the same code retrofitted to use the C# lambda operator (=>). In the code below, notice how
there is no trace whatsoever of the delegate type. Under the hood, the C# compiler generates an appropriate
anonymous method. Recall that C# anonymous methods are just delegates in disguise.\


static void Main(string[] args)
{
List<int> list = new List<int>() {20, 1, 4, 8, 9, 44};   

// Use a C# 3.0 lambda expression.
// Remember that this is just an anonymous method in disguise!
List<int> evenNumbers = list.FindAll(i => (i % 2) == 0);

Console.WriteLine("Here are the even numbers:");
foreach (int evenNumber in evenNumbers)
{
  Console.WriteLine(evenNumber);
}
}



VB programmers can author a very similar code base using the Function statement. Again, notice how you
have no need to author a separate target method for the
Predicate(Of T) delegate. Furthermore, you do not
need to make use of the delegate type whatsoever, similar to a C# anonymous method. The VB compiler will
infer this.


' VB
Option Strict On

Module Program
Sub Main()
  Dim list = New List(Of Integer)()
  list.AddRange(New Integer() {20, 1, 4, 8, 9, 44})

  ' Call FindAll() using a VB lambda.
  Dim evenNumbers As List(Of Integer) = _
    list.FindAll
(Function(i) (i Mod 2) = 0)

  ' Print out the result set.
   
  Console.WriteLine("Here are the even numbers:")
  For Each evenNumber As Integer In evenNumbers
    Console.WriteLine(evenNumber)
  Next
End Sub
End Module
Lambda Expressions
Table of Contents
Copyright (c) 2008.  Intertech, Inc. All Rights Reserved.  This information is to be used exclusively as an
online learning aid.  Any attempts to copy, reproduce, or use for training is strictly prohibited.
Courseware
Training Resources
Tutorials
Services