2009-01-15 28 views
6

这是在我的其他问题中提到的,我认为将它添加到记录可能会有用。在以下程序中,哪些(如果有)本地定义的委托在对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 }); 
     } 
    } 
} 

回答

7

基于什么反射显示,过去两年(a4dummyAgeMatch)由微软的C#3.0编译器缓存(在名为 “CS $ <> 9_CachedAnonymousMethodDelegate5” 和 “CS $ <> 9_CachedAnonymousMethodDelegate6” 的领域我特别的构建)。

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

我不认为该行为是由规范强制的,但单声道编译器的行为方式(具有不同的变量名称)非常相似。

5

那么,回答具体问题:最后两个是唯一被缓存的,因为它们不捕获任何东西。你可以在反射器中看到它(但它不漂亮)。当然,你可以通过在args调整他们使他们重复使用:

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; 

又通thisa1/a3,并locala2。因为他们都没有直接捕获任何东西,所以它们都可以被缓存(至少对我而言,CS$<>9__CachedAnonymousMethodDelegate5CS$<>9__CachedAnonymousMethodDelegate9)。当然,他们然后失去了直接重新分配(先前捕获的)变量的能力,但是FP倡导者不会那样喜欢; -p你总是可以将更新后的值作为返回值传回,或者声明委托类型与ref的论点(我不推荐它,但)。

+0

谢谢 - 这是小说! – xyz 2009-01-15 19:15:24