|
|
|
|
|
Home
»
.NET 3.0/3.5
»
Lambda, Lambda, Lambda - Uncovering the Mystery Behind Lambda Expressions
|
|
|
Author Rank:
|
|
Total page views :
2958
|
|
Total downloads :
24
|
|
|
|
|
Download
Files:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Similar ArticlesMost ReadTop RatedLatest
|
|
|
|
|
|
|
|
|
|

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(); } | So now how do we write our equivalent quadratic expressions using lambdas? Since we are passing in three parameters (a,b,c), we'll need to place this expression on the left side. On the right side, we will place our quadratic expression utilizing these parameters.
QuadraticDelegate quadratic1 = (a, b, c) => (-b + Math.Sqrt(discriminant(a, b, c))) / (2 * a);
The code above is equivalent to our anonymous method below , but some might argue, a lot easier to read (at least for those professors teaching advanced calculus).
QuadraticDelegate quadratic1 = delegate(double a, double b, double c) { return (-b + Math.Sqrt(discriminant(a, b, c))) / (2 * a); }; The full equivalent quadratic example using lambdas is shown in listing 3
Listing 3 - Implementing the quadratic equation using lambda expressions
delegate double QuadraticDelegate(double a, double b, double c); static void Method2() { Console.WriteLine("Method #2");
// create an anonymous delegate to calculate the discriminant using a lambda expression QuadraticDelegate discriminant = (a, b, c) => (b * b - 4d * a * c); // create an anonymous delegate for the quadratic functions using lambdas QuadraticDelegate quadratic1 = (a, b, c) => (-b + Math.Sqrt(discriminant(a, b, c))) / (2 * a); QuadraticDelegate quadratic2 = (a, b, c) => (-b - Math.Sqrt(discriminant(a, b, c))) / (2 * a); // calculate the quadratic roots for x^2 + 5x + 6 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(); } | If we now look at the quadratic using lambdas reinterpreted in redgate's reflector, it does in fact confirm that lambdas are nothing more than anonymous delegates. Our reflector code looks exactly like the code in Method1 shown in listing 1:
Listing 4 - Method Containing Lambda Expressions Reflected through RedGate's Reflector
Function Templates It is sort of painful to have to declare the delegate and then assign it every time you need to use a lambda expression. Microsoft has created these cool templates called Func that seem to generate the delegates for you. We can therefore rewrite listing 3 as follows and avoid needing to create a quadratic delegate outside the method.
Listing 5 - Rewriting the quadratic implementation using the Func<T> delegate
static void Method3() { Console.WriteLine("Method #3");
// create an anonymous delegate to calculate the descriminant Func<double, double, double, double> descriminant = (a, b, c) => (b * b - 4d * a * c); // create an anonymous delegate for the quadratic functions Func<double, double, double, double> quadratic1 = (a, b, c) => (-b + Math.Sqrt(descriminant(a, b, c))) / (2 * a); Func<double, double, double, double> quadratic2 = (a, b, c) => (-b - Math.Sqrt(descriminant(a, b, c))) / (2 * a);
// calculate the quadratic roots for x^2 + 5x + 6 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(); } |
The first 3 double parameters in the Func template are for the 3 doubles passed into the function. The last double parameter is the return value type. Microsoft would have had to create a different Func template for varying number of parameters, so I was curious at what point they stopped creating Func<T> methods. After all there could be an infinite number of Func<T1, T2, T3, T4, T5, ...Result>. The MSDN documentation and intellisense shows a maximum of 4, so I guess my sample came close to hitting the limit. Anyway, below are the results of all three methods of producing the quadratic, and as expected all produce equivalent results .
Figure 1 - Results of running all three delegate methods
Conclusion
This is just the tip of the iceberg of what you can do with lambda expressions, but hopefully this article helps clarify what a lambda expression is used for in C#. Lambda expressions start to get more interesting when you start to take advantage of the closure principle or when you use lambdas with powerful technologies such as LINQ. In the meantime, don't be afraid to delegate your knowledge to your programming tasks and harness the power of lambda in C# and .NET.
|
|
|
Login
to add your contents and source code to this article
|
|
|
|
|
|
|
|
|
|
Mike Gold
Michael Gold is President of Microgold Software Inc., makers of the WithClass UML Tool. His company is a Microsoft VBA Partner and Borland Partner. Mike is a Microsoft MVP and founding member of C# Corner. He has a BSEE and MEng EE from Cornell University and has consulted for Chase Manhattan Bank, JP Morgan, Merrill Lynch, and Charles Schwab. Currently he is a senior developer at Finisar Corp. He has been involved in several .NET book projects, and is currently working on a book for using .NET with embedded systems. He can be reached at mike@c-sharpcorner.com
|
|
|
|
|
|
|
|
|
C# Consulting is founded in 2002 by the founders of C# Corner. Unlike a traditional
consulting company, our consultants are well-known experts in .NET and many of them
are MVPs, authors, and trainers. We specialize in Microsoft .NET development and
utilize Agile Development and Extreme Programming practices to provide fast pace
quick turnaround results. Our software development model is a mix of Agile Development,
traditional SDLC, and Waterfall models.
|
|
Click here to learn more about C# Consulting. |
|
|
|
|
|
|
|
Introducing MaxV - one click. infinite control. Hyper-V Hosting from MaximumASP.
Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon.
Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees.
As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
|
Dynamic PDF
ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications.
|
Go.NET
Build custom interactive diagrams, network, workflow editors, flowcharts, or software design tools. Includes many predefined kinds of nodes, links, and basic shapes. Supports layers, scrolling, zooming, selection, drag-and-drop, clipboard, in-place editing, tooltips, grids, printing, overview window, palette. 100% implemented in C# as a managed .NET Control. Document/View/Tool architecture with many properties&events. Optional automatic layout.
|
Dundas Software
Dundas Chart for .NET is the most advanced .NET charting package available today. With an extremely complete feature set, elegant architecture and easy implementation, Dundas Chart can quickly add advanced Charting functionality to enhance and transform ASP.NET and Windows Forms applications. Whether you are implementing charting into internal projects, or building applications for clients, Dundas Chart offers advanced technology and advanced results to get the most out of data.
|
Clickatell's SMS Gateway
Clickatell's Developer Solutions allow you to SMS enable any website or
application via a range of API's. Learn More about our API connections.
|
Microsoft Visual Studio 2010 Professional
Microsoft Visual Studio 2010 Professional will launch on April 12, but you can beat the rush and secure your copy today by pre-ordering at the affordable estimated retail price of $549 (US). Pre-order now.
|
Nevron Chart for .NET 2010.1 Now Available
The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
|
Developer-Ready ASP.NET 2.0 Web Hosting with 3 MONTHS FREE
Now supporting .NET 3.0 Framework with Windows Workflow Foundation, Windows Communication Foundation (WCF), Windows Presentation Foundation (WPF), windows CardSpace (WCS)! Providing more flexibility for Developers with Web Services Support and a User/Permission Manger. Also supporting MS SQL 2005/2000 with Real-Time Backups, FREE Automated Attach .MDF Tool, FREE SQL Restore and Shrink SQL DB Tools, and SQL
|
|
|
|
|
|
|
|
|
Download
Files:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|