193

Once it is compiled, is there a difference between:

delegate { x = 0; }

and

() => { x = 0 }

?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
MojoFilter
  • 12,256
  • 14
  • 53
  • 61

6 Answers6

147

Short answer : no.

Longer answer that may not be relevant:

  • If you assign the lambda to a delegate type (such as Func or Action) you'll get an anonymous delegate.
  • If you assign the lambda to an Expression type, you'll get an expression tree instead of a anonymous delegate. The expression tree can then be compiled to an anonymous delegate.

Edit: Here's some links for Expressions.

  • System.Linq.Expression.Expression(TDelegate) (start here).
  • Linq in-memory with delegates (such as System.Func) uses System.Linq.Enumerable. Linq to SQL (and anything else) with expressions uses System.Linq.Queryable. Check out the parameters on those methods.
  • An Explanation from ScottGu. In a nutshell, Linq in-memory will produce some anonymous methods to resolve your query. Linq to SQL will produce an expression tree that represents the query and then translate that tree into T-SQL. Linq to Entities will produce an expression tree that represents the query and then translate that tree into platform appropriate SQL.
Amy B
  • 108,202
  • 21
  • 135
  • 185
  • 3
    An Expression type? This sounds like new territory to me. Where can I find out more about Expression types and using expression trees in C#? – MojoFilter Nov 18 '08 at 18:53
  • 2
    Even longer answer - there are fiddly reasons why they're convertible to different delegate types, too :) – Jon Skeet Nov 18 '08 at 19:33
  • Note that the lambda can only be assigned to an Expression type, if it is an expression lambda. – Micha Wiedenmann Nov 08 '16 at 09:07
128

I like Amy's answer, but I thought I'd be pedantic. The question says, "Once it is compiled" - which suggests that both expressions have been compiled. How could they both compile, but with one being converted to a delegate and one to an expression tree? It's a tricky one - you have to use another feature of anonymous methods; the only one which isn't shared by lambda expressions. If you specify an anonymous method without specifying a parameter list at all it is compatible with any delegate type returning void and without any out parameters. Armed with this knowledge, we should be able to construct two overloads to make the expressions completely unambiguous but very different.

But disaster strikes! At least with C# 3.0, you can't convert a lambda expression with a block body into an expression - nor can you convert a lambda expression with an assignment in the body (even if it is used as the return value). This may change with C# 4.0 and .NET 4.0, which allow more to be expressed in an expression tree. So in other words, with the examples MojoFilter happened to give, the two will almost always be converted to the same thing. (More details in a minute.)

We can use the delegate parameters trick if we change the bodies a little bit though:

using System;
using System.Linq.Expressions;

public class Test
{
    static void Main()
    {
        int x = 0;
        Foo( () => x );
        Foo( delegate { return x; } );
    }

    static void Foo(Func<int, int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }

    static void Foo(Expression<Func<int>> func)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

But wait! We can differentiate between the two even without using expression trees, if we're cunning enough. The example below uses the overload resolution rules (and the anonymous delegate matching trick)...

using System;
using System.Linq.Expressions;

public class Base
{
    public void Foo(Action action)
    {
        Console.WriteLine("I suspect the lambda expression...");
    }
}

public class Derived : Base
{
    public void Foo(Action<int> action)
    {
        Console.WriteLine("I suspect the anonymous method...");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int x = 0;
        d.Foo( () => { x = 0; } );
        d.Foo( delegate { x = 0; } );
    }
}

Ouch. Remember kids, every time you overload a method inherited from a base class, a little kitten starts crying.

Amy B
  • 108,202
  • 21
  • 135
  • 185
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 9
    I got out my popcorn and read the whole thing. That's some distinction that I would probably never think about even if I was staring it right in the face. – MojoFilter Nov 18 '08 at 19:40
  • Okay, removing the whiny bit at the end as clearly some people *have* read it :) – Jon Skeet Nov 18 '08 at 19:51
  • 29
    I knew some of this, but I must congratulate you on your ability to communicate it to humans. – Amy B Nov 18 '08 at 20:05
  • 1
    For anybody interested in the changes in .NET 4.0 (based on the CTP) - see http://marcgravell.blogspot.com/2008/11/future-expressions.html . Note that C# 4.0 doesn't do anything new yet as far as I can tell. – Marc Gravell Nov 19 '08 at 08:19
  • 4
    Jon, you rock. Erik, to be a true Skeet fanboi, you should be subscribed to his stack overflow rss like I am. Just stick http://stackoverflow.com/users/22656 into your feed reader. – Paul Batum Nov 19 '08 at 14:26
  • 1
    You: _If you specify an anonymous method without specifying a parameter list_ at all _it is compatible with any delegate type returning void and without any ref/out parameters._ Actually `ref` parameters are OK (the anonymous method without parameter list is still compatible). But with an `out` parameter it can't work, since the body of the method must necessarily use all `out` parameters. – Jeppe Stig Nielsen Feb 13 '13 at 17:52
  • Actually I can write a usual (named) method which doesn't use its `out` parameters by ensuring that the method never returns. I can do this with an infinite loop, or do it by having all execution paths throw an exception. But with the anonymous method, the compiler requires me to specify the parameters if some of them are `out`, even if I don't use them (because my anonymous method can't `return`). So your answer is correct now. – Jeppe Stig Nielsen Feb 13 '13 at 18:04
  • @jon I don't understand - how can `delegate { return x; }` go to `Func action` - the signature is not the same - the latter has _extra_ `int` param type. can you please shed light ? – Royi Namir Apr 23 '14 at 11:07
  • 4
    @RoyiNamir: If you use an anonymous method without a parameter list, that's compatible with *any* delegate type with non-ref/out parameters, so long as the return type is compatible. Basically you're saying "I don't care about the parameters". Note that `delegate { ... }` is *not* the same as `delegate() { ... }` - the latter is only compatible with a parameterless delegate type. – Jon Skeet Apr 23 '14 at 11:42
  • 1
    "Ouch. Remember kids, every time you overload a method inherited from a base class, a little kitten starts crying." I need this on a t-shirt. – mambrow Feb 15 '17 at 15:13
4

In the two examples above there's no difference, zero.

The expression:

() => { x = 0 }

is a Lambda expression with statement body, so it can't be compiled as an expression tree. In fact it doesn't even compile because it needs a semicolon after 0:

() => { x = 0; } // Lambda statement body
() => x = 0      // Lambda expression body, could be an expression tree. 
Matthew
  • 462
  • 8
  • 20
Olmo
  • 4,257
  • 3
  • 31
  • 35
3

Amy B is correct. Note that there can be advantages to using expression trees. LINQ to SQL will examine the expression tree and convert it to SQL.

You can also play tricks with lamdas and expression trees to effectively pass the names of class members to a framework in a refactoring-safe way. Moq is an example of this.

Amy B
  • 108,202
  • 21
  • 135
  • 185
Daniel Plaisted
  • 16,674
  • 4
  • 44
  • 56
-1

There is a difference

Example:

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(delegate
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});   

And I replace with lambda:(error)

var mytask = Task.Factory.StartNew(() =>
{
    Thread.Sleep(5000);
    return 2712;
});
mytask.ContinueWith(()=>
{
    _backgroundTask.ContinueTask(() =>lblPercent.Content = mytask.Result.ToString(CultureInfo.InvariantCulture));
});
nawfal
  • 70,104
  • 56
  • 326
  • 368
-2

Some basics here.

This is a anonymous method

(string testString) => { Console.WriteLine(testString); };

As anonymous methods do not have names we need a delegate in which we can assign both of these methods or expressions. e.g.

delegate void PrintTestString(string testString); // declare a delegate

PrintTestString print = (string testString) => { Console.WriteLine(testString); }; 
print();

Same with the lambda expression. Usually we need a delegate to use them

s => s.Age > someValue && s.Age < someValue    // will return true/false

We can use a func delegate to use this expression.

Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;

bool result = checkStudentAge ( Student Object);
Jereme
  • 630
  • 6
  • 18