Click here to Skip to main content
Email Password   helpLost your password?
[The sample code requires the May 2006 LINQ Preview to be installed in order to work.]

Introduction

This article will introduce you to lambda expressions and expression trees – two new related features coming up in the newest version of C# and the .NET runtime. You will learn how to create them, and how to use them to enhance and simplify your C# code. Knowledge of the concepts behind delegates in the .NET framework is assumed.

Let's start by brushing up on anonymous methods, since the concepts behind them will help in understanding lambda expressions.

Anonymous Methods

.NET 2.0 introduced a new construct: anonymous methods. Instead of declaring a named method in your class and then referencing the method by name when creating a delegate:

bool MatchNumbersBelow10(int n)
{
    return n<10;
}

...

int GetNumber(List<int> numbers)
{
   //gets the first number smaller than 10 in the list
    return numbers.Find(MatchNumbersBelow10);
}

...you can write the method directly where it is used:

int GetNumber(List<int> numbers)
{
   //gets the first number smaller than 10 in the list
  return numbers.Find(
        delegate(int n) 
        { 
            return n<10; 
        }
    );
}

As you can see, in the above sample we are passing in a special kind of nameless inline method as a delegate directly to the numbers.Find() method. The advantages of this "anonymous method" syntax are:

  • You don't have to clutter up your class with private methods that are only used once in order to pass some custom code to a method.
  • The code can be put in the place it's used in, rather than somewhere else in the class.
  • The method doesn't have to be named.
  • The return type is inferred from the signature of the delegate type that the anonymous method is being cast to.
  • You can reference local variables in the "outer" method from within the anonymous method.

    Anonymous Method Rules

    The rules for defining an anonymous method are simple:

    Lambda Expressions

    C# 3.0 and the .NET 3.0 Runtime introduce a more powerful construct that builds on the anonymous method concept. It allows you to pass an inline expression as a delegate, with minimal syntax. Instead of the anonymous method we declared above:

    delegate (int n)
    {
        return n<10;
    }

    ...we can do:

    n =>  n<10 

    It looks shorter and more concise, doesn't it? But how does it work? The basic form for a lambda expression is:

    argument-list => expression

    In the example above, we have an argument named n, implicitly typed as int, then the lambda operator (=>), then an expression which checks to see whether n is smaller than 10. We can use this lambda expression as input for the Find() method:

    //gets the first number smaller than 10 in the list
    int result=numbers.Find( n=> n<10);

    To understand better how the lambda expression syntax differs from the anonymous method syntax, let's turn our example anonymous method:

    delegate(int n)
    {
        return n<10;
    } 

    ...into its lambda-expression equivalent:

    n=> n<10

    We don't need the delegate keyword, so take it out.

    (int n)
    {
        return n<10;
    }

    Let's replace the braces with a => lambda operator to make it an inline lambda expression.

    (int n) => return n<10; 
    

    The return keyword isn't needed (or even legal) because an expression is always a single line of code that returns a value. Also, remove the semicolon, because n<10 is now an expression, not a full statement.

    (int n)=> n<10 

    Now, that's already a usable lambda expression - but we can simplify it just a bit more. The type of the argument can be inferred as well by the compiler, so we can remove the type declaration for the argument.

    (n)=> n<10

    We can also take out the parenthesis now, because we don't give the types of the arguments.

    n=> n<10

    And there's our final lambda expression!

    As you can probably see just by that example, the big advantage of lambda expressions in normal coding is that the syntax is more readable and less verbose. This becomes quickly more important the more complex code becomes. For example, when we just add one more argument, take a look at the difference between the length and readability of an anonymous method vs. a lambda expression:

    //anonymous method
    numbers.Sort(delegate(int x, int y){ return y-x; });
    
    //lambda expression
    numbers.Sort((x,y)=>  y-x); 

    And in a more complex example, with multiple delegate properties, compare anonymous methods:

    ControlTrigger trigger= new ControlTrigger ();
    trigger.When=delegate(Control c, ThemePart t)
    { 
       return c.Enabled && c.MouseOver; 
    };
    trigger.Action=delegate(Control c, ThemePart t)
    { 
      t.Visible=true; 
    };
    trigger.ExitAction=delegate(Control c, ThemePart t) 
    { 
       t.Visible=false;
    };

    ...with lambda expressions:

    ControlTrigger trigger=new ControlTrigger();
    trigger.When=(c,t)=>          c.Enabled && c.MouseOver;
    trigger.Action=(c,t)=>         t.Visible=true;
    trigger.ExitAction=(c,t)=>  t.Visible=false;

    Features and Rules

    Return type and name cannot be specified explicitly (just as with anonymous methods). The return type is always inferred from the delegate signature, and there is no need for a name since the expression is always handled as a delegate.

    You can omit parentheses for the argument list if the expression has one argument:

    n => n<10

    ...unless its argument has an explicitly-declared data type:

    //Type explicitly declared for an argument - have to include parentheses!
    (string name)=> "Name: " + name
    

    If the expression has more than one argument or has no arguments, you must include the parentheses.

    A lambda expression doesn't have to return a value if the signature of the delegate it is being cast to has a return type of void:

    delegate void EmptyDelegate();
    …
    EmptyDelegate dlgt= ()=> Console.WriteLine("Lambda without return type!");

    The code used in a lambda doesn't have to be a single statement. You can include multiple statements if you enclose them inside a statement block:

    Action<Control> action= 
       control=>
       {
           control.ForeColor=Color.DarkRed;
           control.BackColor=Color.MistyRose;
       });

    In this form, the lambda more closely resembles an anonymous method, but with a less verbose syntax.

    Lambda statement blocks are not supported by the VS IDE in the LINQ Preview, so they will be underlined as a syntax error. However, they will compile and run correctly in spite of the IDE's lack of support.

    You can access local variables and arguments in the outer method from within the expression, just as you can do with anonymous methods.

    void GetMatchesFromList(List<int> matchValues)
    {
      List<int> numbers=GetNumbers(); //Get a list of numbers to search in.
      //Get the first number in the numbers list that is also contained in the 
      //matchValues list.
      int result=numbers.Find(n=> matchValues.Contains(n));
    }

    Uses

    Lambda expressions are nifty anywhere you need to pass a little bit of custom code to a component or method. Where anonymous methods were useful in C# 2.0, lambda expressions really shine in C# 3.0.

    Some examples are expressions for filtering, sorting, iterating, converting, and searching lists (using the useful methods introduced in .NET 2.0):

    List<int> numbers=GetNumbers();
    
    //find the first number in the list that is below 10
    int match=numbers.Find(n=> n<10);
    
    //print all the numbers in the list to the console
    numbers.ForEach(n=> Console.WriteLine(n));
    
    //convert all the numbers in the list to floating-point values
    List<float> floatNumbers=numbers.ConvertAll<float>(n=> (float)n);
    
    //sort the numbers in reverse order
    numbers.Sort((x, y) => y-x);
    
    //filter out all odd numbers
    numbers.RemoveAll(n=> n%2!=0);

    ...progress update handlers passed to a long-running method:

    metafileConverter.Convert(filename, 
    percentComplete=> progressBar.Value=percentComplete);

    ...and simple event handlers:

    slider.ValueChanged+= (sender, e)=> label.Text=slider.Value.ToString(); 

    XLinq, MS's new technology for querying XML documents, and Linq, MS's new technology for querying object collections, use lambda expressions heavily.

    How to Use Lambda Expressions

    When the upcoming version of .NET is released, using lambda expressions will be as simple as declaring them in the places you would normally use anonymous methods or delegates:

    //passing a method as a delegate
    int match=numbers.Find(MatchNumbersUnder10);
    
    //passing an anonymous method as a delegate
    int match=numbers.Find(delegate(int n) { return n<10; });
    
    //passing a lambda expression as a delegate
    int match=numbers.Find(n=>  n<10); 

    Currently, though, you must take some additional steps. The LINQ Preview must be installed on your machine, and you must create a project using one of the LINQ project templates so that VS will know to use the C# 3 compiler included with the LINQ Preview installation.

    Lambda Expression Trees

    There's another powerful feature of lambda expressions that is not obvious at first glance. Lambda expressions can be used as expression trees (hierarchies of objects defining the components of an expression – operators, property access sub-expressions, etc) instead of being directly turned to code. This way, the expressions can be analyzed at runtime.

    To make a lambda expression be treated as an expression tree, assign or cast it to the type Expression<T>, where T is the type of the delegate that defines the expression's signature.

    Expression<Predicate<int>> expression = n=>  n<10;

    The expression tree created by the expression defined above looks like this:

    Sample image

    As you can see, Expression<T> class has a property called Body, which holds the top level expression object in the expression tree. In the case of the expression above, it is a BinaryExpression with a NodeType of ExpressionType.LT (LessThan). The BinaryExpression object has a Left property that contains the sub-expression to the left of the operator – in this case, a ParameterExpression whose Name property is set to "n". It also has a Right property that contains the sub-expression to the right of the operator – in this case, a ConstantExpression whose value is 10.

    This expression tree can also be created manually like this:

    Expression<Predicate<int>> expression = Expression.Lambda<Predicate<int>>(
                     Expression.LT(
                              Expression.Parameter(typeof(int), "n"),
                              Expression.Constant(10)
                    ),
                   Expression.Parameter(typeof(int), "n")
       );
    

    An expression tree can be compiled and turned into a delegate using the Compile() method of the Expression<T>class:

    //Get a compiled version of the expression, wrapped in a delegate
    Predicate<int> predicate=expression.Compile();
    //use the compiled expression
    bool isMatch=predicate(8); //isMatch will be set to true

    The Compile() method dynamically compiles IL code based on the expression, wraps it in a delegate so that it can be called just like any other delegate, and then returns the delegate.

    Uses

    As shown above, the properties of the expression tree objects can be used to get detailed information about all parts of the expression. This information can be used to translate the expression into another form, extract dependency information, or do other useful things. Microsoft's Database Language-Integrated Query (DLinq) technology, to be introduced in the upcoming version of the .NET Runtime, is based on translation of lambda expressions to SQL at runtime.

    I am working on a component that will allow you to do simple automatic binding via expressions, like this):

    Binding binding=new Binding<Entry, Label>();
    binding.SourceObject=src;
    binding.DestObject=dest;
    binding.SourceExpression=(src,dest)=> src.Name + 
        " – added on "+src.Date.ToString();
    binding.DestExpression=(dest)=>dest.Text;
    binding.Bind(); 

    The Binding object would analyze the expression tree specified in the SourceExpression property, find all binding dependencies (in this case the Name and Date properties of the source object), attach listeners to their property change events (NameChanged and DateChanged, or else PropertyChanged), and set the property specified in the destination expression when the events are raised to keep the property value of the destination up-to-date.

    Another usage would be a dynamic filter that automatically keeps a list control up-to-date based on changes to the text entered in a filter textbox. All you would have to do to set up the dynamic filter would be:

    listControl.Filter=(item)=> item.Name.StartsWith(textBox.Text);

    Whenever textbox.Text changes, the filter expression would be run on all the items, and those not matching the filter expression would be hidden.

    Another thing that expression trees are potentially useful for is lightweight dynamic code generation. You can build an expression tree manually as I described above, then call Compile() to create a delegate, and then call it to run the generated code. It is much easier to use expression tree objects to generate code than to try to output the IL manually.

    Conclusion

    As you can see, lambda expressions and expression trees open a lot of new possibilities! I am excited to work with them and to see the uses other developers think of for them.

  • You must Sign In to use this message board.
     
     
    Per page   
     FirstPrevNext
    General5 from me
    dybs
    16:57 19 Nov '09  
    Excellent, easy to follow article! I was introduced to lambas in college, but never really got them until now. Thanks!

    The Expression class is good to know about, too. A co-worker and I wrote an equation parser attached to a third-party editor, and this Expression could definitely simplify our evaluation code!

    Thumbs Up

    Dybs

    The shout of progress is not "Eureka!" it's "Strange... that's not what i expected". - peterchen

    GeneralGreat introduction
    Option Greek
    5:46 28 Oct '09  
    I wish more articles on CP and other places (msdn especially) would be written in this style. It's very simple, clear and readable.
    Dunlap,
    You would make a good technical writer Smile

    Thanks!
    GeneralRe: Great introduction
    J. Dunlap
    9:36 9 Nov '09  
    Thanks for the kind words! Smile I wrote it because when I learned about them, none of the articles I had seen quite had everything... I'd be a tech writer by trade except it doesn't make as much as programming Wink so instead I get hired to develop software and then get assigned to do the documentation at my software development rate. Smile
    GeneralThank you for the great introduction!
    antecedents
    10:53 25 Jan '08  
    This was the type of introduction I was hoping to find earlier when I set out to discover what Lambda expressions are all about! The article was excellent; great work!
    GeneralRe: Thank you for the great introduction!
    J. Dunlap
    9:33 9 Nov '09  
    Thanks for the kind words! Smile
    GeneralOne query over lambda statements
    sreeshti
    2:51 21 May '07  
    Hello ,

    Article is interesting. I refer to it many times whenever I need some info. I am new to linq and trying my hands on Lambda expression. Now I am stuck with a problem -


    Is it possible to create a

    System.Expression.Expression Object which contains a lambda Statement body.



    I simple tried with this code -

    Expression> expr = {Console.WriteLine(x); return x;}

    It simply refuse to work. I think there must be some other way to create such an expression.



    Please guide me.


    Thanks

    Pankaj

    Generalsmall problem....
    Jeff Brush
    12:09 7 May '07  
    Great article, and nice intro, but there's a problem:

    First, the ExpressionType is Expression.LessThan, not Expression.LT.

    But more importantly, expression.Compile() fails with a "Lambda Parameter not in scope" message. Any idea why? I've been extending your ideas on my own and getting that message so I decided to try your simple example and it didn't work!!


    GeneralNice article.
    Stephen Hewitt
    18:37 28 Mar '07  
    A very interesting article; good work.


    Steve

    GeneralMy 5 as well
    Shoki
    7:51 22 Mar '07  
    Nicely written article.

    Ashok
    Real Programmer's do not comment their code, if it is hard to write then it should hard to understand

    GeneralDo you know how to do runtime queries using IQuerable
    Sacha Barber
    2:40 16 Mar '07  
    Great article but do you know how to do runtime queries using IQuerable

    I am banging my head on this.

    I want to use standard LINQ and found this blog

    http://blogs.msdn.com/mattwar/archive/2006/05/10/oops-we-did-it-again.aspx
    which kind of talks about this. BUt I cant get it too work.

    Do you have any ideas.

    An example would be great.



    sacha barber

    GeneralGreat article
    Judah Himango
    5:35 23 Feb '07  
    You explained things in a really simple way with simple code snippets. Good article, have a 5.

    Tech, life, family, faith: Give me a visit.
    I'm currently blogging about: The Lord's Prayer in Aramaic song (audio) The apostle Paul, modernly speaking: Epistles of Paul
    Judah Himango


    GeneralVery Cool
    Wes S
    18:21 13 Feb '07  
    Special thanks on the part of expression trees. Glad to have read it.

    Wes
    General5!
    lxwde
    17:11 12 Feb '07  
    Thanks for your article.
    Glad to know there is an Expression<T> class in the .NET framework.;)
    GeneralFuntionalProgramming
    Sacha Barber
    8:46 10 Feb '07  
    Gotta love this functional (Haskell) types programming.

    We did a hole module on this at UNI, curries / lambdas / Lazy evaluation there are all part of Haskell.


    Dont ya just love linkq/and Xlinq though.

    sacha barber

    GeneralExcellent article
    peterchen
    4:19 10 Feb '07  
    Thanks!


    Developers, Developers, Developers, Developers, Developers, Developers, Velopers, Develprs, Developers!
    We are a big screwed up dysfunctional psychotic happy family - some more screwed up, others more happy, but everybody's psychotic joint venture definition of CP
    Linkify!|Fold With Us!

    GeneralBoost::lambda
    Coolboy123
    0:29 10 Feb '07  
    Boost::lambda Always the Best!!!
    GeneralRe: Boost::lambda
    Stuart Dootson
    22:09 14 Feb '07  
    errrm - not when compared to facilities built into the language. Don't get me wrong - I loves me Boost, but things like lambda I'd rather have as part of C++.


    GeneralSmall correction
    reinux
    13:02 9 Feb '07  
    Nice article, another 5 Smile

    Small correction near the beginning of the article for a common mistake:
    C# 3.0 and the .NET 3.0 Runtime introduce a more powerful construct that builds on the anonymous method concept.
    LINQ actually runs on the .NET 2.0 runtime, and .NET 2.0 is all that you need installed for LINQ and LINQ projects to work. .NET 3.0 is just WinFX, which isn't required by LINQ. This can be sort of crucial to know for embedded applications and Mono and such.

    I complained to Microsoft about this ridiculous confusion before: http://www.petitiononline.com/winfx/petition.html[^]
    GeneralRe: Small correction
    Judah Himango
    10:11 14 Feb '07  
    reinux wrote:
    .NET 2.0 is all that you need installed for LINQ and LINQ projects to work


    I don't mean to nitpick, but that's not entirely true. LINQ requires some extra libraries (think System.Query.dll) which define types like Func delegates and all its overloads, as well as extension methods to IEnumerable and IList objects. So, it will be .NET framework 3.5 running on CLR 2. Confusing enough? Big Grin

    Tech, life, family, faith: Give me a visit.
    I'm currently blogging about: One can only dream (no income taxes) The apostle Paul, modernly speaking: Epistles of Paul
    Judah Himango


    GeneralRe: Small correction
    reinux
    10:18 14 Feb '07  
    Ah right D'Oh!

    .NET Framework 3.5 running C# 3.0 code on CLR 2.0, without needing .NET 3.0.

    Grrr....
    GeneralRe: Small correction
    Judah Himango
    12:09 14 Feb '07  
    reinux wrote:
    .NET Framework 3.5 running C# 3.0 code on CLR 2.0, without needing .NET 3.0.


    Afraid so! Poke tongue

    Tech, life, family, faith: Give me a visit.
    I'm currently blogging about: One can only dream (no income taxes) The apostle Paul, modernly speaking: Epistles of Paul
    Judah Himango



    Last Updated 14 Mar 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010