2009-01-15 17 views
6

Cela a été mentionné dans mon autre question et j'ai pensé qu'il pourrait être utile de l'ajouter à l'enregistrement. Dans le programme suivant, lequel, le cas échéant, des délégués définis localement sont mis en cache entre les appels à la méthode Work au lieu d'être créés à partir de zéro à chaque fois?Quels délégués (le cas échéant) définis localement sont mis en cache entre les appels de méthode?

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

Répondre

7

Sur la base de ce que montre réflecteur, les deux derniers (a4 et dummyAgeMatch) sont mises en cache par le compilateur MS C# 3.0 (dans les champs appelés "CS < $> 9_CachedAnonymousMethodDelegate5" et "CS < $> 9_CachedAnonymousMethodDelegate6" en ma construction particulière).

Ces peuvent être mis en cache, alors que les autres dépendent évidemment des variables capturées.

Je ne crois pas que le comportement soit mandaté par la spécification, mais le compilateur Mono se comporte de la même manière (avec des noms de variables différents).

5

Eh bien, pour répondre à la question spécifique: les deux derniers sont les seuls qui sont mis en cache, puisqu'ils ne capturent rien. Vous pouvez le voir dans le réflecteur (mais ce n'est pas joli). Bien sûr, vous pouvez les modifier à faire les réutilisables en passant dans 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; 

Et passer this dans a1/a3 et local en a2. Parce qu'aucun d'entre eux ne capture plus directement rien, ils peuvent tous être mis en cache (CS$<>9__CachedAnonymousMethodDelegate5 à CS$<>9__CachedAnonymousMethodDelegate9 pour moi, au moins). Bien sûr, ils perdent alors la possibilité de réattribuer directement la variable (précédemment capturée), mais les avocats FP ne l'aimeront pas de toute façon ;-p Vous pouvez toujours passer la valeur mise à jour comme valeur de retour, ou déclarer un type de délégué avec ref arguments (je ne le recommande pas, cependant).

+0

Merci - c'est nouveau! – xyz