Introduction
At first glance, a lambda expression looks like something your professor may have written on the blackboard in calculus class, but in reality, it is "syntactic sugar" built into the C# language over delegates. In this article, we will begin to explore the nuances of lambda expressions by seeing how they they relate to delegates and how they can be used to implement a popular mathematical formula, the quadratic equation.
What is a delegate?
A delegate is nothing more than a function pointer in C#. Unlike the function that sits in your C# class, a delegate can be passed around like any other variable or property. Why would you want to pass around a function? The advantage of passing around a function, is that you can dynamically have it execute wherever you want inside of your code. Jeremy Miller just wrote a great article in MSDN (Oct 2009) on how you can use lamdbas (a.k.a. delegates) for various tasks such as helping you reduce code duplication, passing expressions into filters, generating calls from a separate thread into your UI thread, and more. Delegates have opened C# up to the world of functional programming, so we .NET programmers now have at our disposal the richness of object-oriented mechanisms along with the power of functional constructs.
Delegates describe the signature of the function you want to pass around your program. In the case of the quadratic formula, we need to pass in 3 parameters to produce our resulting roots. The delegate for a quadratic looks something like this:
delegate double QuadraticDelegate(double a, double b, double c);
Note that the delegate differs from an actual function in that you need to "new up" a delegate instance and give it a function. The function can either take the form of an existing method in your class, or it can be an anonymous method. An anonymous method defines the delegate without requiring an existing method. In an anonymous method, you simply define the implementation when you are constructing the delegate instance.
In our first attempt at implementing the quadratic formula, we use 3 anonymous methods. The first anonymous method calculates the discriminant of the quadratic formula. The discriminant is then used by the quadratic formula anonymous methods to calculate the two roots of the equation. Note that none of the delegates actually implement the formula, they just create the implementations needed to run against parameters a,b, and c. Implementing the delegate is performed the same way you would call any other method, by passing values to the delegate.
Listing 1 - Implementing the quadratic formula with anonymous methods
| delegate double QuadraticDelegate(double a, double b, double c); static void Method1() { Console.WriteLine("Method #1"); // create an anonymous method to calculate the discriminant QuadraticDelegate discriminant = delegate(double a, double b, double c) {return (b * b - 4d * a * c);}; // create an anonymous method for the quadratic functions QuadraticDelegate quadratic1 = delegate(double a, double b, double c) { return (-b + Math.Sqrt(discriminant(a, b, c))) / (2 * a); }; QuadraticDelegate quadratic2 = delegate(double a, double b, double c) { return (-b - Math.Sqrt(discriminant(a, b, c))) / (2 * a); }; // calculate the quadratic roots for x^2 + 5x + 6 by implementic the delegates instances. double val1 = quadratic1(1d, 5d, 6d); double val2 = quadratic2(1d, 5d, 6d); Console.WriteLine("Roots are {0}, {1}", val1, val2); // calculate the quadratic roots for x^2 + 40x + 6 double val3 = quadratic1(1d, 40d, 6d); double val4 = quadratic2(1d, 40d, 6d); Console.WriteLine("Roots are {0}, {1}", val3, val4); Console.ReadLine(); } |
Using Lambda Expressions to Implement delegates
A lambda expression is a fancy way of writing anonymous methods. First let's look at a simple lambda expression and understand what it does.
The expression
x => x + 1 can simply be redefined as the anonymous method delegate(int x) { return (x + 1);}
of course, for the lambda expression to be fully resolved, you would need to assign the lambda expression to the delegate it is implementing.
delegate int SumInt(int num);
SumInt result = x => x + 1;
otherwise we have no way of resolving whether x is an integer, double, or other type. There are a few ways you can write the lambda expression x => x + 1 as shown in listing 2 below, all are equivalent.
Listing 2 - Multiple ways to write the lambda expression x => x + 1
| delegate int SumInt(int num); static void LambdaSample() { SumInt val1 = (x) => x + 1; Console.WriteLine("val = {0}", val1(1)); Console.ReadLine(); SumInt val2 = x => x + 1; Console.WriteLine("val = {0}", val2(1)); Console.ReadLine(); SumInt val3 = (int x) => x + 1; Console.WriteLine("val = {0}", val3(1)); Console.ReadLine(); } |

danny droreditedPosted Nov 3, 2009, 2:32 PMEdited Nov 3, 2009, 2:33 PM
I wonder... is it possible to use Func< ... > for making a function with no return value? --------------------------------------------------- Danny, Business loan, Unsecured loans and Fire Sprinklers