2013-09-24 1 views
0

J'ai cette logique assez simple:Portée et méthodes anonymes

class Program 
{ 
    static void Main(string[] args) 
    { 
     using (TransactionScope ts = new TransactionScope()) 
     { 
      System.Threading.Tasks.Parallel.Invoke(() => 
       { 
        TransactionScope y = ts; 
        System.Diagnostics.Debug.WriteLine("Test"); 
       }, 
       () => 
       { 
        System.Diagnostics.Debug.WriteLine("Test"); 
       } 
      ); 
      ts.Complete(); 
     }   
    } 
} 

Si vous placez des points d'arrêt sur les deux Debug.WriteLine() déclarations, vous remarquerez que quand il se casse le premier, les deux y et ts sont répertoriés comme locaux par le débogueur. Mais quand il frappe le point d'arrêt dans ce dernier, ts ne figure pas en tant que local et en outre, en ajoutant ts à la fenêtre de la montre donne The name 'ts' does not exist in the current context.

Est-ce capture variable dans l'action ou est-ce un autre mécanisme? J'ai regardé autour de writeups sur la capture de variables et je ne trouve rien qui indique explicitement que les variables ne sont capturées que lorsqu'elles sont utilisées, mais je fais l'hypothèse que cela s'appelle la capture de variables parce qu'elle ne "capture" que il a besoin et ne garde pas de références à tout ce qui est disponible.

+0

Je pense que le code tel qu'il est écrit risque d'appeler 'Complete' avant que les actions éventuellement parallèles soient terminées. – Kit

+0

@Kit, De la docs pour Parallel.Invoke: 'Cette méthode ne retourne pas jusqu'à ce que chacune des opérations fournies est terminée, indépendamment de savoir si l'achèvement se produit en raison de terminaison normale ou exceptionnelle.» – Pete

+0

Oh duh. J'ai oublié ça. Merci pour le rappel. – Kit

Répondre

3

Je fais l'hypothèse qu'il appelle la capture de variable car elle ne « capture » ce dont il a besoin et qui ne garde pas de références à tout disponible

C'est tout à fait exact. Le code du refacteur du compilateur qui se referme sur une variable pour le garder dans la portée. Il ne ferme pas toutes les variables externes lorsqu'une méthode anonyme est utilisée.

Prenons l'exemple suivant:

public static void Foo() 
{ 
    int i = 0; 
    int j = 1; 
    Action a =() => Console.WriteLine(i); 
} 

Il sera transformé en quelque chose comme ce qui suit par le compilateur:

public class ClosureClass1 
{ 
    public int i; 

    public void Method1() 
    { 
     Console.WriteLine(i); 
    } 
} 

public static void Foo() 
{ 
    ClosureClass1 closure = new ClosureClass1(); 
    closure.i = 0; 
    int j = 1; 
    Action a = closure.Method1; 
} 

Vous devriez être en mesure de voir, à partir de cet exemple, pourquoi la fermeture les champs au-dessus sont accessibles et les champs non fermés d'une portée externe ne le sont pas.

+0

Ajout de lambda avec aucune variable capturée aussi à titre d'exemple serait encore mieux. '[CompilerGenerated] private void CompilerGeneratedName() { Debug.WriteLine (" Test "); } 'Dans la même classe de type de boîtier –

Questions connexes