Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are lambdas constructors for delegate types?

I've discovered that Rhino Mocks' AssertWasCalled fails when I use lambdas as parameters to the method being asserted.

TEST :
_mockDoer.AssertWasCalled(x => x.Print(y => Console.WriteLine("hi")));

CODE INSIDE SYSTEM UNDER TEST :
_doer.Print(y => Console.WriteLine("hi")));

This has made me think of lambdas as, effectively, constructors for delegate types.

Am I missing anything important when I think of lambdas as constructors for delegate types?

like image 620
lance Avatar asked Sep 22 '11 14:09

lance


People also ask

Are lambdas delegates?

Again, lambdas are just delegates, which means that they can be used as an event handler without any problems, as the following code snippet illustrates. The += operator in this context is used to subscribe to an event.

How you can assign a lambda expression to a delegate?

You can substitute a named method for a lambda expression when you call the Select method: Filter f = x => x % 2 == 0; List<int> even = Select( _numbers, f ); The snippet shows that you're defining a variable f of type Filter and assigning a lambda expression to it. You then use the delegate to call the Select method.

How are an anonymous delegate and a lambda expression related?

Anonymous Method is an inline code that can be used wherever a delegate type is expected. Microsoft introduced Anonymous Methods in C# 2.0 somewhere around 2003. Lambda expression is an anonymous method that you can use to create delegates or expression tree types.

What is the use of lambda expression in C#?

Lambda expressions and tuples The C# language provides built-in support for tuples. You can provide a tuple as an argument to a lambda expression, and your lambda expression can also return a tuple. In some cases, the C# compiler uses type inference to determine the types of tuple components.


2 Answers

Well, they're not really "constructors" in any of the normal uses of the word "constructor".

They're expressions which can be converted to delegate types or expression tree types - the latter being essential when it comes to out-of-process LINQ.

If you're really asking whether it's expected that using two "equivalent" lambda expressions can create unequal delegate instances: yes, it is. IIRC, the C# language specification even calls out that that's the case.

However, using the same lambda expression more than once won't always create different instances:

using System;

class Test
{
    static void Main(string[] args)
    {
        Action[] actions = new Action[2];
        for (int i = 0; i < 2; i++)
        {
            actions[i] = () => Console.WriteLine("Hello");
        }
        Console.WriteLine(actions[0] == actions[1]);
    }
}

On my box, that actually prints True - actions[0] and actions[1] have the exact same value - they refer to the same instance. Indeed, we can go further:

using System;

class Test
{
    static void Main(string[] args)
    {
        object x = CreateAction();
        object y = CreateAction();
        Console.WriteLine(x == y);
    }

    static Action CreateAction()
    {
        return () => Console.WriteLine("Hello");
    }
}

Again, this prints True. It's not guaranteed to, but here the compiler has actually created a static field to cache the delegate the first time it's required - because it doesn't capture any variables etc.

Basically this is a compiler implementation detail which you should not rely on.

like image 88
Jon Skeet Avatar answered Oct 14 '22 05:10

Jon Skeet


Just to expand on Jon's (excellent, as always) answer: in current implementations of C#, if "the same" lambda appears in two different source code locations then the two lambdas are never realized into equal delegates. However, we reserve the right to in the future detect this situation and unify them.

Whether the converse holds or not is also implementation-dependent. If two delegates are created from a lambda at a particular source code position, the delegates might or might not have equality. There are some scenarios where it is impossible for the delegates to have equality (because they are closed over different instances of local variables, for example). In situations where it is possible for them to have equality, most of the time they do, but there are a few cases where we could perform this optimization and do not, just because the compiler is not yet sophisticated enough.

like image 24
Eric Lippert Avatar answered Oct 14 '22 06:10

Eric Lippert