Sunteți pe pagina 1din 5

16/4/2014

Exploring Lambda Expression in C# - CodeProject


10,544,055 members (65,352 online) Sign in

home

articles

quick answers

discussions

features

community

help

Search for articles, questions, tips

Articles Languages C# Delegates and Events

Next

Article Browse Code Bugs / Suggestions Stats Revisions Alternatives Comments (18)

Exploring Lambda Expression in C#


By Zeeshan Jafar Hirani, 12 Mar 2008
4.57 (60 votes) Rate this:

About Article
This article covers things from syntax to constraints and implementation details for lambda expression in C# Type Licence First Posted Views Bookmarked Article CPOL 10 Mar 2008 281,581 170 times

Introduction
Lambda expression is an inline delegate introduced with C # 3.0 language. Its a concise way to represent an anonymous method. It provides a syntax to create and invoke functions. Although Lambda expressions are simpler to use than anonymous methods, they do slightly differ on how they are implemented. Both anonymous methods and Lambda expressions allow you define the method implementation inline, however, an anonymous method explicitly requires you to define the parameter types and the return type for a method. Lambda expression uses the type inference feature of C# 3.0 which allows the compiler to infer the type of the variable based on the context. Lambda expression can be broken down into parameters followed by execution code. e.g.:
Collapse | Copy Code

Share

C#3.0 C# .NET Dev Intermediate

P a r a m e t e r= >e x e c u t i o n c o d e .

The left hand side represents zero or more parameters followed by the lambda symbol = >which is used to separate the declaration of a parameter from the implementation of the method. Lambda expression is then followed by the statement body. Lambda expression allows us to pass functions as arguments to a method call. I will start with a simple example of lambda expression which returns even numbers from a list of integers.
Collapse | Copy Code

/ / s i m p l ee x a m p l eo fl a m b d ae x p r e s s i o n . p u b l i cs t a t i cv o i dS i m p l e L a m b d E x p r e s s i o n ( ) { L i s t < i n t >n u m b e r s=n e wL i s t < i n t > { 1 , 2 , 3 , 4 , 5 , 6 , 7 } ; v a re v e n s=n u m b e r s . F i n d A l l ( n= >n%2= =0 ) ; v a re v e n s 2=n u m b e r s . F i n d A l l ( ( i n tn )= >{r e t u r nn%2= =0 ;} ) ; O b j e c t D u m p e r . W r i t e ( e v e n s ) ; O b j e c t D u m p e r . W r i t e ( e v e n s 2 ) ; }

Looking at the first lambda expression assigned to the e v e n svariable, you will notice few things that are different from anonymous methods. First, we are not using d e l e g a t e keyword anywhere in our code. Second, we are not defining the parameter and return types because the compiler infers the type based on context. The types in the expression are determined by the d e l e g a t e definition. So in this case return type specified by the F i n d A l lmethod takes a d e l e g a t e which takes an i n t parameter and returns boolean. Lambda expression without braces and return type, provides the most concise way to represent anonymous methods. If the number of parameters is one then you can omit the parentheses surrounding the parameter as demonstrated in the first lambda expression. Although lambda expression does not require explicit parameters, you have the option to define the parameters, braces and return type as shown in the second lambda expression assigned to the e v e n 2variable. Notice that we are using the explicit parameter of i n t and also use the return type as we usually specify in a method. The return statement would not work if you do not enclose the execution code with parentheses considering that you are fully qualifying everything that attributes a method. Another place where parentheses are required in lambda expressions is when you want to use a parameter in multiple blocks of code inside the lambda expression such as follows:
Collapse | Copy Code

d e l e g a t ev o i dW r i t e M u l t i p l e S t a t e m e n t s ( i n ti ) ; p u b l i cs t a t i cv o i dM u l t i p l e S t a t e m e n t s I n L a m d a s ( ) { W r i t e M u l t i p l e S t a t e m e n t sw r i t e=i= > { C o n s o l e . W r i t e L i n e ( " N u m b e r"+i . T o S t r i n g ( ) ) ; C o n s o l e . W r i t e L i n e ( " N u m b e r"+i . T o S t r i n g ( ) ) ; } ; w r i t e ( 1 ) ; }

Top News
C# 6: First reactions
Get the Insider News free each morning.

Related Videos

http://www.codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C

1/8

16/4/2014

Exploring Lambda Expression in C# - CodeProject

In the above code sample, we have enclosed our code in curly brackets so that we can use the parameter in both the expressions. If there were no curly brackets, the compiler wouldn't be able to recognize the variable i . You can use lambda expressions where a delegate may not have any parameter. In that case, you have to supply a pair of empty parentheses to signify a method with no parameter. Here is a simple example which illustrates a lambda with no parameter.
Collapse | Copy Code

Related Articles
Lambda Expressions Explicating the new C++ standard (C++0x), and its implementation in VC10 Way to Lambda Lambda Expressions and Expression Trees: An Introduction C++11 Lambda Storage Without libc++ Understand Lambda Expressions in 3 minutes Strong: Reflection without magic strings using of lambda expression and removing foreach/for loop Using lambdas - C++ vs. C# vs. C++/CX vs. C++/CLI Expression Tree Lambda Simplified Sexy C# C# Delegates, Anonymous Methods, and Lambda Expressions O My! Functional programming in C# Concepts behind the C# 3.0 language Factorial Simplified using lambda CLinq - LINQ support for the C++/CLI language Generate AST for the DLR Replacing foreach loop with LINQ LINQ to Life

d e l e g a t ev o i dL a m b d a s N o P a r a m s ( ) ; p u b l i cs t a t i cv o i dL a m b d a s W i t h N o P a r a m e t e r ( ) { L a m b d a s N o P a r a m sn o p a r a m s=( )= >C o n s o l e . W r i t e L i n e ( " h e l l o " ) ; n o p a r a m s ( ) ; }

C# 3.0 defines the number of generic delegates that you can assign to your lambda expression instead of v a rkeyword which infers the type. Let's take a look at an example of using a few of those generic delegates:
Collapse | Copy Code

p u b l i cs t a t i cv o i dG e n e r i c D e l e g a t e s ( ) { L i s t < i n t >n u m b e r s=n e wL i s t < i n t >{1 ,2 ,3 ,4 ,5 ,6 ,7} ; F u n c < i n t ,b o o l >w h e r e=n= >n<6 ; F u n c < i n t ,i n t >s e l e c t=n= >n ; F u n c < i n t ,s t r i n g >o r d e r b y=n= > n%2= =0?" e v e n ":" o d d " ; v a rn u m s=n u m b e r s . W h e r e ( w h e r e ) . O r d e r B y ( o r d e r b y ) . S e l e c t ( s e l e c t ) ; O b j e c t D u m p e r . W r i t e ( n u m s ) ; }

In the above example, we are using three different extension methods: w h e r e ,o r d e r b yand s e l e c t . The w h e r e extension method takes a generic d e l e g a t e with i n tparameter and a return type of boolean to identity if a certain element be included in the output sequence. The s e l e c textension method takes an integer parameter and returns an integer, but it could return anything that you want the result to be transformed into before being sent to the output sequence. In the o r d e r b y extension method, we are taking the integer parameter and using it to identify if it is even or odd. Based on that, we sort the results. It would have been extremely cumbersome if we had to define three different d e l e g a t e s for each of these lambda expressions. With the introduction of generic d e l e g a t e s in C# 3.0, it is fairly non trivial to assign our lambda expressions to generic d e l e g a t e s and pass those d e l e g a t e s to the extension methods. Generic d e l e g a t e s come in pretty handy and help you avoid writing common d e l e g a t e s which was common in .NET 1.1 and .NET 2.0 (since there were no generic d e l e g a t e s that came out of the box). Generic d e l e g a t e s allow you to define up to 4 parameters and 1 return type so you can have a d e l e g a t e that may look something like this:
Collapse | Copy Code

Related Research

F u n c < i n t ,b o o l ,s t r i n g ,d o u b l e ,d e c i m a l >t e s t ;

Essential Keys to Mobile Usability

If your method or d e l e g a t e does not meet the criteria then you have to manually declare a d e l e g a t e that takes those parameters. Generic d e l e g a t e s usually cover majority of scenarios but in cases where it does not meet your needs, feel free to write a custom d e l e g a t e . There are cases where type inference may not return the data type that you really want the lambda expression to return. In those cases, we can explicitly specify the parameter type on the lambda expression. For example:
Collapse | Copy Code

F u n c < d o u b l e ,i n t >e x p r=( x )= >x/2 ;

Protecting Your Business Data: Five Dos and Donts

The above expression returns a compiler error because by dividing a d o u b l e , the inferred type is actually going to be d o u b l e . However, you are assigning the lambda expression to a d e l e g a t e that has a return type of i n t . If i n t is what you really want to return from the method, then you are better off casting the expression body to i n t to indicate your intent as shown below:
Collapse | Copy Code

F u n c < d o u b l e ,i n t >e x p r=( x )= >( i n t ) x/2 ;

http://www.codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C

2/8

16/4/2014

Exploring Lambda Expression in C# - CodeProject


Lambda expressions are basically of two types. One is considered a simple expression where everything is inferred and consists of an expression only. The second type of lambda expression is statement blocks which are composed of braces and return type. Let's write a lambda expression in both forms to see the difference:
Collapse | Copy Code

Learn Agile: Ten Tips for Launching and Testing High Quality Apps for the American Market

/ / e x a m p l es h o w i n gt w ot y p e so fl a m b d ae x p r e s s i o n s p u b l i cs t a t i cv o i dE x p l i c i t P a r a m e t e r s I n L a m b d a E x p r e s s i o n ( ) { F u n c < i n t ,i n t >s q u a r e=x= >x*x ; F u n c < i n t ,i n t >s q u a r e 1=( x )= >{r e t u r nx*x ;} ; E x p r e s s i o n < F u n c < i n t ,i n t > >s q u a r e e x p r=x= >x*x ; } E x p r e s s i o n < F u n c < i n t ,i n t > >s q u a r e 2=( i n tx )= >{r e t u r nx*x ;} ; / / d o e sn o tc o m p i l e . Protecting Android Applications with Secure Code Signing Certificates

Let's go ahead and dissect each lambda expression one at a time. The first lambda expression is considered a simple expression which does not have a statement body because there is no return statement and braces whereas the second lambda statement includes a statement body because it has a return statement and braces. Although both get compiled to a delegate, the benefit of lambda expressions without a statement body is that it can be converted to an expression tree which a certain provider can use to generate its own implementation. This is much like LINQ to SQL will convert the expression tree to its domain specific language called SQL, and send it to the database. The third lambda expression is really where lambda expression shies from an anonymous method. The beauty of this statement is the fact that you can easily convert to an expression whereas anonymous methods can only be converted to d e l e g a t e s. What is also great is that an expression can be converted back to a d e l e g a t e by compiling the expression to d e l e g a t e with the following syntax:
Collapse | Copy Code

F u n c < i n t , i n t >s q=s q u a r e e x p r . C o m p i l e ( ) ;

The last lambda expression raises an exception because the compiler cannot convert a lambda expression that contains a statement body, as you can observe from the fact that it is surrounded by braces and a return statement. Although you can use lambda expressions to generate expression trees, there is nothing preventing you from directly creating your own expression tree. Lets walk through an example of creating an expression tree for a lambda expression s q u a r e=x= >x*x .
Collapse | Copy Code

/ / e x a m p l ec r e a t e se x p r e s s i o nt r e eo fx* x p u b l i cs t a t i cv o i dC r e a t i n g E x p r e s s i o n T r e e ( ) { P a r a m e t e r E x p r e s s i o np a r a m e t e r 1=E x p r e s s i o n . P a r a m e t e r ( t y p e o f ( i n t ) ," x " ) ; B i n a r y E x p r e s s i o nm u l t i p l y=E x p r e s s i o n . M u l t i p l y ( p a r a m e t e r 1 ,p a r a m e t e r 1 ) ; E x p r e s s i o n < F u n c < i n t ,i n t > >s q u a r e=E x p r e s s i o n . L a m b d a < F u n c < i n t ,i n t > > ( m u l t i p l y ,p a r a m e t e r 1 ) ; F u n c < i n t ,i n t >l a m b d a=s q u a r e . C o m p i l e ( ) ; C o n s o l e . W r i t e L i n e ( l a m b d a ( 5 ) ) ; }

You first start off with a parameter expression of type i n t .


Collapse | Copy Code

P a r a m e t e r E x p r e s s i o np a r a m e t e r 1=E x p r e s s i o n . P a r a m e t e r ( t y p e o f ( i n t ) ," x " ) ;

The next step is to build the body of lambda expressions which happens to be a binary expression. The body consists of a multiply operator to the same parameter expression.
Collapse | Copy Code

B i n a r y E x p r e s s i o nm u l t i p l y=E x p r e s s i o n . M u l t i p l y ( p a r a m e t e r 1 ,p a r a m e t e r 1 ) ;

The final step is to build the lambda expression which combines the body with the parameter as follows:
Collapse | Copy Code

E x p r e s s i o n < F u n c < i n t ,i n t > >s q u a r e=E x p r e s s i o n . L a m b d a < F u n c < i n t ,i n t > > ( m u l t i p l y , p a r a m e t e r 1 ) ;

The last step converts the expression to d e l e g a t e and executes the d e l e g a t e as follows:
Collapse | Copy Code

F u n c < i n t ,i n t >l a m b d a=s q u a r e . C o m p i l e ( ) ; C o n s o l e . W r i t e L i n e ( l a m b d a ( 5 ) ) ;

Creating An Expression from Another Expression


You can take an expression tree and modify it to create another expression from it. In the following example, we will start off with a lambda expression of x * x and then modify this expression to add 2 to it. Lets have a look at an example:
Collapse | Copy Code

p u b l i cs t a t i cv o i dC r e a t i n g A n E x p r e s s i o n F r o m A n o t h e r E x p r e s s i o n ( ) { E x p r e s s i o n < F u n c < i n t ,i n t > >s q u a r e=x= >x*x ; B i n a r y E x p r e s s i o ns q u a r e p l u s 2=E x p r e s s i o n . A d d ( s q u a r e . B o d y , E x p r e s s i o n . C o n s t a n t ( 2 ) ) ; E x p r e s s i o n < F u n c < i n t ,i n t > >e x p r=E x p r e s s i o n . L a m b d a < F u n c < i n t ,i n t > > ( s q u a r e p l u s 2 , s q u a r e . P a r a m e t e r s ) ; F u n c < i n t ,i n t >c o m p i l e=e x p r . C o m p i l e ( ) ;

http://www.codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C

3/8

16/4/2014
}

Exploring Lambda Expression in C# - CodeProject


C o n s o l e . W r i t e L i n e ( c o m p i l e ( 1 0 ) ) ;

We start off with a lambda expression which returns a s q u a r e :


Collapse | Copy Code

E x p r e s s i o n < F u n c < i n t ,i n t > >s q u a r e=x= >x*x ;

Next we generate the body of the new lambda expression by using the body of the first lambda expression and adding a constant of 2 to it and assigning it to the binary expression:
Collapse | Copy Code

B i n a r y E x p r e s s i o ns q u a r e p l u s 2=E x p r e s s i o n . A d d ( s q u a r e . B o d y ,E x p r e s s i o n . C o n s t a n t ( 2 ) ) ;

In the last step, we generate the new lambda expression by combining the body with the parameters from the first lambda expression. The important point which I discovered in the statement below is that, a parameter's reference needs to be exactly the same from the first lambda expression which is s q u a r e . P a r a m e t e r s . You cannot create a new instance of p a r a m e t e r s collection which results in a runtime error.
Collapse | Copy Code

E x p r e s s i o n < F u n c < i n t ,i n t > >e x p r=E x p r e s s i o n . L a m b d a < F u n c < i n t ,i n t > > ( s q u a r e p l u s 2 , s q u a r e . P a r a m e t e r s ) ;

Closures and Lambda Expressions


Closure is a concept that comes from functional programming. It essentially captures or uses the variable which is outside the scope of the lambda expression. What it essentially means is you can use variables inside the lambda expression that are declared outside the scope of the lambda expression you are able to use and capture the variable that is outside the scope of the lambda expression. This has its advantages but could lead to issues as well since the outside context has the ability to change the variable value. Lets drill through an example of lambda expression in the context of closure.
Collapse | Copy Code

p u b l i cs t a t i cv o i dL a m b d a W i t h C l o s u r e ( ) { i n tm u l i t p l y b y=2 ; F u n c < i n t ,i n t >o p e r a t i o n=x= >x*m u l i t p l y b y ; C o n s o l e . W r i t e L i n e ( o p e r a t i o n ( 2 ) ) ; }

In the above example, we are using the m u l i t p l y b y variable inside the lambda expression although it is declared outside the scope of the expression. This concept is called variable capture. In the background, C# compiler takes all those captured variables and puts them in a generated class. When you are using lambda expressions with outside variables, they are not picked up by the garbage collector, and are forced to hang around until they are used by the lambda expressions and the expression goes out of scope. There are certain restrictions when you are using a lambda expression with a parameter with r e fand o u t keyword. When your variable is passed with r e f or o u tkeyword, you must explicitly specify the parameter type because the compiler cannot infer the type of the variable. As shown in the example below:
Collapse | Copy Code

d e l e g a t ev o i dO u t P a r a m e t e r ( o u ti n ti ) ; d e l e g a t ev o i dR e f P a r a m e t e r ( r e fi n ti ) ; p u b l i cs t a t i cv o i dG o t c h a s W i t h L a m b d a s ( ) { / / e x a m p l ew i t ho u tp a r a m e t e ri n ti ; O u t P a r a m e t e rs o m e t h i n g=( o u ti n tx )= >x=5 ; s o m e t h i n g ( o u ti ) ; C o n s o l e . W r i t e L i n e ( i ) ; / / e x a m p l ew i t hr e fp a r a m e t e r . i n ta=2 ; R e f P a r a m e t e rt e s t=( r e fi n tx )= >x + + ; t e s t ( r e fa ) ; C o n s o l e . W r i t e L i n e ( a ) ;

Notice in the above code, I am explicitly specifying the parameter type of i n t in both cases, r e fand o u t . If I omit the parameter type, the compiler will raise an error. Another restriction that I have come across using lambdas is you cannot use the p a r a m skeyword in the parameter type for a lambda expression regardless of whether or not you explicitly specify the type of the parameter. The following code does not compile because the parameter definition is attributed with p a r a m s keyword:
Collapse | Copy Code

d e l e g a t ev o i dP a r m s P a r a m e t e r ( p a r a m si n t [ ]i n t s ) ; p u b l i cs t a t i cv o i dL a m b d a W i t h P a r a m ( ) { P a r m s P a r a m e t e rp a r=( p a r a m si n t [ ]i n t s )= > { f o r e a c h( i n tii ni n t s ) { C o n s o l e . W r i t e L i n e ( i ) ; } } ; }

Summary
http://www.codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C 4/8

16/4/2014

Exploring Lambda Expression in C# - CodeProject


In this article I introduced the syntax of a lambda expression how it replaces anonymous methods. We also talked about how lambda expressions differ from anonymous methods because of the type inference, and its ability to be easily transformed into delegates or expression trees. We learned the parameter restrictions of lambda expressions and how to write an expression from scratch and compile it to a delegate and vice versa.

History
10 March, 2008: Article posted 12 March, 2008: Article updated

License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Zeeshan Jafar Hirani


Software Developer (Senior) Tarrant Regional Water District United States General Certificate of Education obtained in Math, Physics, Chemistry, Principle of Accounts & Statistics in the year 1998-99 from the University of Cambridge, London, England. Earned a degree in Business Administration in Information System with a GPA of 3.6 on 4.0 scales from Univ. of Texas At Arlington in Honors in the year 2005. Certified MCAD,MCSD,MCPD ,OCP (Oracle Certified Professional),MCDBA. I have been working as an Asp.net C# developer for last 3 years. Zeeshan Hirani Senior Asp.net Developer Tarrant Regional Water District zhirani@trwd.com http://www.trwd.com

Article Top

PDF Viewer for .NET


gdpicture.com Display PDF in your application using vb.net or C#. Royalty free !

Comments and Discussions


You must Sign In to use this message board. Search this forum Profile popups Spacing Compact Noise High Layout Open All Per page 50 Go Update

First Prev Next

nice

Shahriar_cse

11-Oct-13 9:30

Nice article
Sign In View Thread Permalink

My vote of 5

ioan.bucur

12-Aug-13 21:15

I found out new things about lambda expression limitations. Thanks!

http://www.codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C

5/8

S-ar putea să vă placă și