lambda 构造函数是否适用于委托类型?

发布于 2024-12-06 03:34:56 字数 371 浏览 1 评论 0原文

我发现当我使用 lambda 作为断言方法的参数时,Rhino Mocks 的 AssertWasCalled 会失败。

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

待测系统内的代码:
_doer.Print(y => Console.WriteLine("hi")));

这让我将 lambda 视为委托类型的构造函数。

当我将 lambda 视为委托类型的构造函数时,我是否遗漏了一些重要的内容?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怀中猫帐中妖 2024-12-13 03:34:56

嗯,在“构造函数”这个词的任何正常用法中,它们并不是真正的“构造函数”。

它们是可以转换为委托类型或表达式树类型的表达式 - 后者对于进程外 LINQ 至关重要。

如果您确实想知道使用两个“等效”的 lambda 表达式是否可以创建不相等的委托实例:是的,确实如此。 IIRC(C# 语言规范)甚至指出情况就是如此。

但是,多次使用相同的 lambda 表达式并不总是会创建不同的实例:

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]);
    }
}

在我的盒子上,实际上会打印 True - actions[0] 和 actions[1] 具有完全相同的值 - 它们引用相同的实例。事实上,我们可以更进一步:

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");
    }
}

再次打印 True。不能保证,但这里编译器实际上创建了一个静态字段来在第一次需要时缓存委托 - 因为它不捕获任何变量等。

基本上这是一个编译器实现细节你不应该依赖。

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.

柠檬 2024-12-13 03:34:56

只是为了扩展 Jon 的(一如既往的优秀)答案:在当前的 C# 实现中,如果“相同”的 lambda 出现在两个不同的源代码位置,那么这两个 lambda 永远不会实现为相等的委托。但是,我们保留将来发现这种情况并统一它们的权利。

反过来是否成立也取决于实现。如果在特定源代码位置从 lambda 创建两个委托,则这些委托可能相等,也可能不相等。在某些情况下,委托不可能具有相等性(例如,因为它们对局部变量的不同实例是封闭的)。在它们可能可能相等的情况下,大多数情况下都是如此,但在某些情况下我们可以执行此优化,但不这样做,只是因为编译器还不够复杂。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文