2011-02-09 3 views
0

Par exemple, est-il nécessaire d'ajouter une instance de Timer à une liste comme je le fais ici pour éviter que le Timer soit collecté? Tyme si le rappel n'était pas anonyme l'aswer est oui, mais comme il est anonyme j'imagine que les variables dans le bloc de méthode qui sont accessibles dans le bloc de méthode anonyme ne seront collectées que lorsque la méthode anonyme sera terminée? Dans ce cas, pas besoin d'enregistrer ref comme je le fais ..:Quand les variables de méthode, accessibles dans une méthode anonyme, sont-elles collectées?

private static List<Timer> timers = new List<Timer>(); 

public static void RunCallbackAfter(Action callback, int secondsToWait) 
{ 
     Timer t = null; 
     t = new Timer(new TimerCallback(delegate(object state) 
      { 
       SomeThread.BeginInvoke(callback); 
       timers.Remove(t); 
      }), null, secondsToWait*1000, Timeout.Infinite); 
     timers.Add(t); 
} 

Répondre

2

Les objets référencés par les variables capturées dans la méthode anonyme ne seront pas éligibles pour la récupération de place tant que le délégué créé par la méthode anonyme n'est pas éligible pour la récupération de place.

Cependant, si elle est seulement la Timer qui a une référence au délégué, et rien n'a d'autre référence à la minuterie, alors je soupçonne les deux seraient admissibles à la collecte des ordures, en supposant que cela est en effet le genre de minuterie dont vous avez besoin pour garder une référence. (Je crois me rappeler que certains minuteries font exigent et certains ne pas. Je ne me souviens pas qui est qui.)

En outre, si vous avez supprimé l'appel de timers.Remove(t) dans la méthode anonyme puis en premier lieu ne serait pas capturer t. Ce n'est que capturé variables qui ont une durée de vie prolongée ... pas chaque variable dans la méthode qui contient la méthode anonyme.

0

Non Vous n'êtes pas obligé de planquer votre minuterie. Il devrait normalement être collecté, car il est seulement référencé par votre délégué. Cependant, je crois que le constructeur Timer place une référence avec le runtime sous-jacent, donc ça devrait aller.

Eric Lippert a probablement quelque chose à dire dans son blog: The implementation of anonymous methods in C# and its consequences (part 1)

Votre Timer variable de t restera accessible aussi longtemps que il y a une référence à votre méthode anonyme. Votre méthode anonyme restera référencée jusqu'à ce que l'événement ait été déclenché. Au moins aussi longtemps. Selon Eric Lippert, le compilateur C# transforme votre code en quelque chose d'autre, avec le contexte de votre méthode (y compris le pointeur this de l'objet englobant) tout enveloppé dans sa propre petite classe générée par le compilateur. Il semble donc que la méthode anonyme (ou délégué) elle-même contient la référence à la minuterie. Oh, et tous les autres membres de ce fil sont corrects: j'ai juste laissé échapper quelques trucs (et j'ai appris comment le compilateur C# gère les méthodes anonymes en même temps).

Alors oui, vous avez une référence circulaire. Mais je suis assez sûr que la création d'une minuterie devrait s'accrocher quelque part dans le runtime/windows. Ayons un chèque. En utilisant Reflector, vous pouvez suivre le chemin de System.Timer.Timer() à TimerBase, qui a une méthode extern AddTimerNative. Je ne sais pas trop comment y jeter un coup d'œil, mais je parie que cela enregistre votre minuterie avec le système d'exploitation.

Conclusion: Votre temporisateur ne sortira pas de la portée, car il sera référencé par le système d'exploitation jusqu'à ce qu'il se déclenche.

+0

hein? s'il vous plaît eloborate – markmnl

+0

ahh .. Je vois un _closure_ est le nom des variables accessibles à partir de la méthode anonyme – markmnl

+1

Cependant, le rappel et le minuteur forment une référence circulaire; s'il y avait une référence extérieure au rappel, il n'y aurait pas de problème (sauf qu'il faudrait toucher la variable extérieure pour s'assurer que c'est dans la fermeture) ... – bdonlan

0

En général, les fonctions anonymes en C# maintiendront toutes les variables locales en référence jusqu'à ce que la fonction anon elle-même soit détruite. Naturellement, supprimer l'appel de suppression dans ce cas supprimerait la référence, ce qui signifie que la variable ne serait plus maintenue en vie par le rappel.

Cependant, ceci forme ici une référence circulaire; sauf s'il existe une référence externe, le temporisateur et le rappel peuvent être détruits simultanément. Je ne suis pas sûr que le fait de commencer une minuterie compte comme une référence externe qui la maintient en vie en C#, donc je ne peux pas répondre complètement à votre question, cependant. Si un minuteur démarré est traité comme ayant une référence externe, alors seul le minuteur et le rappel restent actifs.

Questions connexes