代理缓存行为更改在Roslyn [英] Delegate caching behavior changes in Roslyn

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

问题描述

给定以下代码:

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

使用VS2013,.NET 4.5。当查看反编译的代码时,我们可以看到编译器在调用点处缓存委托

Using VS2013, .NET 4.5. When looking at the decompiled code, we can see that the compiler is caching the delegate at the call site:

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



查看Roslyn反编译的代码A HREF =http://tryroslyn.azurewebsites.net/#K4Zwlgdg5gBAygTxAFwKYFsDcAoADsAIwBswBjGUogQxBBgGEYBvbGNmfYsmANwHswAExgBZABQBKGK3Yt283lQBOMAB4wAvDACsOBewCCpZGD4QAPJGQA+GFWOmImmAk236ZkHyKoAdAHUlMDQAGUhUMQQJPXYAX2xYoAAA> 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?

编辑

This issue talks about the same behavior as asked here.

推荐答案

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

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

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

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要求,指定如何传递参数,如何返回结果,通过寄存器传递哪些参数,以及如何this通过等等。违反这些规则可能会对依赖堆栈行走的工具(如调试器)产生不良影响。

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.

现在,如果实现方法是一个实例方法,需要在代理中发生的是修补this,这是Invoke时的委托实例,成为封闭的Target对象。在这一点上,由于一切已经在它需要的地方,委托可以直接跳转到实现方法体。在许多情况下,这显然比如果实现方法是静态方法需要发生的工作少。

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.

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

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