在罗斯林代表缓存行为变化 [英] Delegate caching behavior changes in Roslyn

查看:262
本文介绍了在罗斯林代表缓存行为变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于以下code:

public class C
{
    public void M()
    {
        var x = 5;
        Action<int> action = y => Console.WriteLine(y);
    }
}

使用VS2013,.NET 4.5。当看到反编译code,我们可以看到,编译器缓存代理的在调用点:

public class C
{
    [CompilerGenerated]
    private static Action<int> CS$<>9__CachedAnonymousMethodDelegate1;
    public void M()
    {
        if (C.CS$<>9__CachedAnonymousMethodDelegate1 == null)
        {
            C.CS$<>9__CachedAnonymousMethodDelegate1 = new Action<int>(C.<M>b__0);
        }
        Action<int> arg_1D_0 = C.CS$<>9__CachedAnonymousMethodDelegate1;
    }
    [CompilerGenerated]
    private static void <M>b__0(int y)
    {
        Console.WriteLine(y);
    }
}

看同code反编译的罗斯林(使用<一个href="http://tryroslyn.azurewebsites.net/#K4Zwlgdg5gBAygTxAFwKYFsDcAoADsAIwBswBjGUogQxBBgGEYBvbGNmfYsmANwHswAExgBZABQBKGK3Yt283lQBOMAB4wAvDACsOBewCCpZGD4QAPJGQA+GFWOmImmAk236ZkHyKoAdAHUlMDQAGUhUMQQJPXYAX2xYoAAA"相对=nofollow> TryRoslyn ),得到以下输出:

Looking at the same code decompiled in Roslyn (using TryRoslyn), yields the following output:

public class C
{
    [CompilerGenerated]
    private sealed class <>c__DisplayClass0
    {
        public static readonly C.<>c__DisplayClass0 CS$<>9__inst;
        public static Action<int> CS$<>9__CachedAnonymousMethodDelegate2;
        static <>c__DisplayClass0()
        {
            // Note: this type is marked as 'beforefieldinit'.
            C.<>c__DisplayClass0.CS$<>9__inst = new C.<>c__DisplayClass0();
        }
        internal void <M>b__1(int y)
        {
            Console.WriteLine(y);
        }
    }
    public void M()
    {
        Action<int> arg_22_0;
        if (arg_22_0 = C.<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 == null)
        {
            C.<>c__DisplayClass0.CS$<>9__CachedAnonymousMethodDelegate2 = new Action<int>(C.<>c__DisplayClass0.CS$<>9__inst.<M>b__1);
        }
    }
}

我们现在可以看到的委托,现在提升到一个私有的类里面 C ,关闭了一个实例变量的时候,我们已经习惯了看到了类似的行为/场(关闭)。

We can now see that the delegate is now lifted into a private class inside C, a similar behavior that we're used to seeing when closing over an instance variable / field (closure).

我知道的,这是一个实现细节可能会有所变动,在任何给定的时间。

I know this is an implementation detail which may be subject to change at any given time.

不过我在想,什么是解除委托到一个新的类和缓存它有过简单地在调用点缓存它的好处是什么?

Still I wonder, what are the benefits of lifting the delegate into a new class and caching it there over simply caching it at the call site?

编辑:

大约相同的行为这个问题会谈在这里问。

推荐答案

是的。最重要的是,包含的lambda实现方法现在是一个实例方法。

Yes. The most important part is that the method containing lambda implementation is now an instance method.

您可以看到一个委托作为中间人接收通过调用一个实例调用调度根据实现方法的调用约定这一呼吁。

You can see a delegate as a middleman receiving an instance call through Invoke and dispatching that call according to the calling convention of the implementing method.

请注意,有指定参数如何传递,如何返回结果的平台ABI的要求,什么参数通过寄存器和哪些过去了,怎么这个被传递等。违反这些规则可能对依赖于堆栈行走的工具,如调试器坏的影响。

Note that there are platform ABI requirements that specify how arguments are passed, how results are returned, what arguments are passed via registers and in which ones, how "this" is being passed and so on. Violating these rules may have bad impact on tools that rely on stack-walking, such as debuggers.

现在,如果实现方法是一个实例方法,需要发生里面的委托是修补本,这是在调用的时候委托实例,是封闭的目标对象的唯一的事。在这一点上,因为其他一切都已经在那里它需要,委托可以直接跳转到执行方法体。在许多情况下,这比什么都需要发生,如果实现方法是一个静态方法的工作明显较少。

Now, if the implementing method is an instance method, the only thing that needs to happen inside the delegate is to patch "this", which is the delegate instance at the time of Invoke, to be the enclosed Target object. At that point, since everything else is already where it needs to be, the delegate can jump directly to the implementing method body. In many cases this is noticeably less work than what would need to happen if the implementing method was a static method.

这篇关于在罗斯林代表缓存行为变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆