Posts Tagged 'Lambda Expressions'

Lambda Expressions in C#

Next week I’m teaching Learning Tree course 2620: .NET 4 Programming for Existing .NET Developers. Maybe the hardest part of that course to understand is lambda expressions. Hopefully, this post will help explain them.

Getting Started with Lambda Expressions

Let’s say you have the simple class shown below.

class Calculator 
{ 
 public static double Add(double x, double y) 
 { 
 return x + y; 
 } 
} 

There’s nothing special here.  To call the Add() method, use the following code:

double answer; 
answer = Calculator.Add(2, 3); 
Console.WriteLine(answer);   // outputs 5 

Delegates

If you wanted to, you could invoke the method using a delegate.  A delegate is “an object-oriented, type-safe pointer to a function” (I read that somewhere). To use the delegate, you first need to define it as shown below.

delegate double MathDelegate(double x, double y); 

This delegate becomes a data type in your program.  Like any other data type, you can declare a variable of the delegate’s type.   You don’t point that variable to an object though; you point it at a function.  The function must match the delegate’s signature (in this case it has to be a function that returns a double and takes two doubles as arguments).  Once the delegate instance is pointing at the function, use the Invoke() method to call the function, supply the arguments, and the result is returned.  The code is shown below.

MathDelegate AddFunction = Calculator.Add; 
answer = AddFunction.Invoke(4, 5); 
Console.WriteLine(answer);  // outputs 9 

Now you’re thinking, “but why would I ever do that?”  Hold on, it gets better.

Anonymous Functions

Notice, the delegate in the prior code is pointing to the Add() method which exists in the Calculator class.  You could create what’s call an anonymous function inline and point a delegate instance to it.  An anonymous function is a function without a name.  It is created with the delegate keyword in C#.  In the code below, an anonymous function is created to multiply, instead of add, the numbers.

 MathDelegate MultiplyFunction = 
 delegate(double x, double y) { return x * y; }; 
answer = MultiplyFunction.Invoke(6, 7); 
Console.WriteLine(answer); // outputs 42 

The following fragment is the important part of the code above:

delegate(double x, double y) { return x * y; }; 

The delegate keyword is used to define the function.  The function has two arguments (x and y) and a function body where the numbers are multiplied.  What it doesn’t have is a name.  Since it is assigned to the delegate instance, it can be invoked through the delegate as shown above.

There’s a shorter syntax to defining the anonymous function in C#.  It uses the => operator.  The sample below does exactly the same thing as the prior example (only it divides the numbers).

MathDelegate DivideFunction = (x, y) => x / y; 
answer = DivideFunction.Invoke(8, 4); 
Console.WriteLine(answer); // outputs 2 

You may be wondering how the system knows x and y are doubles.  That is inferred from the argument data types defined in the delegate MathDelegate.

Now, let’s isolate these two important lines:

MathDelegate MultiplyFunction = 
 delegate(double x, double y) { return x * y; }; 
MathDelegate DivideFunction = (x, y) => x / y; 

Both lines above are creating anonymous functions, and both anonymous functions match the signature of the delegate defined earlier.  The second one is just more compact.

Now you’re thinking, “Are we done yet?”  No, there’s more.

Finally, a Lambda Expression

Inside the Calculator class, you could add the following method which expects three arguments: the two numbers you are going to do math on, and a MathDelegate that is going to do the work.

public static double Evaluate( 
 MathDelegate mathFunction, double x, double y) 
{ 
 return mathFunction.Invoke(x, y); 
} 

Notice, inside the Evaluate() method the function passed as an argument is simply invoked.

Now, you can call the Evaluate() method using the following syntax:

MathDelegate DivideFunction = (x, y) => x / y; 
answer = Calculator.Evaluate(DivideFunction, 100, 10); 
Console.WriteLine(answer);  // outputs 10 

Remember, the Evaluate() method is inside the Calculator class.

In the above code, DivideFunction is just a temporary variable.  You don’t need it and could just define the anonymous function inside the argument list when calling the Evaluate() method as shown below.

answer = Calculator.Evaluate((x, y) => x / y, 144, 12); 
Console.WriteLine(answer); // outputs 12 

Hooray, a lambda expression!  A lambda expression is an anonymous function passed as an argument to another function. But wait, there’s even more.  Go get another cup of coffee.

Generic Delegates

Let’s say you want to make the Calculator more flexible, so not only can you use Evaluate() to do math on two numbers, but also to do math on a single number.  For example, you want to be able to square or cube a number, as well as add or multiple two numbers.  To do this, you can overload the Evaluate() method.  You could define more delegates as shown earlier, but there’s an easier and more confusing way 🙂  In .NET, there is a generic type called Func<>; that is used to define delegates in a flexible way.  When using Func<>, you specify the arguments and the return type.  This defines the generic delegate.

Recall, earlier the MathDelegate type was defined as shown below.

delegate double MathDelegate(double x, double y); 

Using the Func<> generic type, you could define the delegate as follows without creating your own type:

Func<double, double, double> mathFunction 

This creates a generic delegate with two arguments of the type double, and it returns a double.  The last type specified is the return type.

So, let’s now add the overloaded Evaluate() method to the Calculator class as shown below.

public static double Evaluate(Func<double, double> mathFunction, double x) 
{ 
 return mathFunction.Invoke(x); 
} 

In the code below, the Evaluate() methods and lambda expressions are used to divide two numbers or to square a single number.

// Here two numbers are divided 
answer = Calculator.Evaluate((x, y) => x / y, 144, 12); 
Console.WriteLine(answer); // outputs 12 
// Here a single number is squared 
answer = Calculator.Evaluate((x)=>; x*x, 12); 
Console.WriteLine(answer); // outputs 144 

Summary

If you wanted to, you could create more overloads to do math on integers, dates, arrays, collections, Orders and so on.  The client code is responsible for supplying the lambda expressions that determine what is actually done to the data.

Some of you might be thinking, “this is just polymorphism, and I don’t need lambda expressions for this.”  You would be correct, but lambda expressions provide another way of making code more flexible.

Hopefully, this makes some sense.  You can download the code from my web site at http://www.drehnstrom.com/downloads/LambdaExpressions.zip.

Doug Rehnstrom


Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 210 IT training and Management courses, including a full curriculum of .NET training courses.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 29 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

%d bloggers like this: