开发者

Are lambdas constructors for delegate types?

开发者 https://www.devze.com 2023-04-07 07:13 出处:网络
I\'ve discovered that Rhino Mocks\' AssertWasCalled fails when I use lambdas as parameters to the method being asserted.

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.WriteLi开发者_Python百科ne("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?


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号