在方法调用之间缓存哪些(如果有)本地定义的委托?

问题描述 投票:0回答:2

这在我的另一个问题中提到过,我认为将其添加到记录中可能会有用。在下面的程序中,哪些本地定义的委托(如果有)在 Work 方法的调用之间被缓存,而不是每次都从头开始创建?

namespace Example
{
    class Dummy
    {
        public int age;
    }

    class Program
    {
        private int field = 10;

        static void Main(string[] args)
        {
            var p = new Program();

            while (true)
            {
                p.Work();
            }
        }

        void Work()
        {
            int local = 20;

            Action a1 = () => Console.WriteLine(field);
            Action a2 = () => Console.WriteLine(local);
            Action a3 = () => Console.WriteLine(this.ToString());
            Action a4 = () => Console.WriteLine(default(int));
            Func<Dummy, Dummy, bool> dummyAgeMatch = (l, r) => l.age == r.age;

            a1.Invoke();
            a2.Invoke();
            a3.Invoke();
            a4.Invoke();
            dummyAgeMatch.Invoke(new Dummy() { age = 1 }, new Dummy(){ age = 2 });
        }
    }
}
c# caching delegates
2个回答
7
投票

根据 Reflector 显示的内容,最后两个(

a4
dummyAgeMatch
)由 MS C#3.0 编译器缓存(在我的特定字段中名为“CS$<>9_CachedAnonymousMethodDelegate5”和“CS$<>9_CachedAnonymousMethodDelegate6”的字段)构建)。

这些可以被缓存,而显然其他的依赖于捕获的变量。

我不认为规范强制要求这种行为,但 Mono 编译器的行为方式大致相同(具有不同的变量名称)。


5
投票

好吧,回答具体问题:最后两个是唯一被缓存的,因为它们不捕获任何内容。您可以在反射器中看到这一点(但它并不漂亮)。当然,您可以通过传入参数来调整它们,使它们可重复使用: Action<Program> a1 = p => Console.WriteLine(p.field); Action<int> a2 = i => Console.WriteLine(i); Action<Program> a3 = p => Console.WriteLine(p.ToString()); Action a4 = () => Console.WriteLine(default(int)); Func<Dummy, Dummy, bool> dummyAgeMatch = (l, r) => l.age == r.age;

并将 
this

传递到

a1
/
a3
,并将
local
传递到
a2
。因为它们不再直接捕获任何内容,所以它们都可以被缓存(至少对我来说
CS$<>9__CachedAnonymousMethodDelegate5
CS$<>9__CachedAnonymousMethodDelegate9
)。当然,他们随后就失去了直接重新分配(之前捕获的)变量的能力,但 FP 拥护者无论如何都不会喜欢这样;-p 你总是可以将更新后的值作为返回值传递回来,或者声明一个委托类型带有
ref
参数(不过我不推荐)。
    

© www.soinside.com 2019 - 2024. All rights reserved.