2009-01-15 12 views
6

Esto fue mencionado en mi otra pregunta y pensé que podría ser útil agregarlo al registro. En el siguiente programa, ¿cuáles de los delegados definidos localmente, si corresponde, se almacenan en caché entre las llamadas al método de trabajo en lugar de crearse desde cero cada vez?¿Qué delegados (definidos localmente) se almacenan en caché entre las llamadas a métodos?

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

Respuesta

7

en base a lo Reflector espectáculos, los dos últimos (a4 y dummyAgeMatch) se almacenan en caché por el compilador MS C# 3.0 (en campos llamados "CS $ <> 9_CachedAnonymousMethodDelegate5" y "CS $ <> 9_CachedAnonymousMethodDelegate6" en mi construcción particular).

Estos pueden ser almacenados en caché, mientras que obviamente los otros dependen de las variables capturadas.

No creo que el comportamiento sea obligatorio por la especificación, pero el compilador Mono se comporta de la misma manera (con diferentes nombres de variable).

5

Bueno, para responder a la pregunta específica: los dos últimos son los únicos que se almacenan en caché, ya que no capturan nada. Puedes ver esto en el reflector (pero no es bonito). Por supuesto, usted puede ajustar a hacen re-utilizable pasando en 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; 

y pasar this en a1/a3, y local en a2. Debido a que ninguno de ellos captura directamente nada más, todos pueden almacenarse en caché (CS$<>9__CachedAnonymousMethodDelegate5 hasta CS$<>9__CachedAnonymousMethodDelegate9 para mí, al menos). Por supuesto, luego pierden la capacidad de reasignar la variable (previamente capturada) directamente, pero a los defensores de la PF les va a gustar eso de todos modos ;-p Siempre puedes volver a pasar el valor actualizado como un valor de retorno, o declarar un tipo de delegado con ref argumentos (aunque no lo recomiendo).

+0

Gracias - ¡eso es novedoso! – xyz

Cuestiones relacionadas