J'ai le code suivant:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
this.FoundStep += delegate(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.Start();
return retval;
}
Remarquez comment j'enregistre mon membre d'événement (FoundStep) à la fonction anonyme locale sur place.
Ma question est: quand la fonction 'FindStepByType' prendra fin - la fonction anonyme sera-t-elle supprimée automatiquement de la liste des délégués de l'événement ou dois-je la supprimer manuellement avant de quitter la fonction? (et comment je fais ça?)
J'espère que ma question était claire.
Votre code a quelques problèmes (certains que vous et d'autres avez identifiés):
Pour résoudre ce problème, et toujours utiliser un délégué anonyme, affectez-le à une variable locale, puis supprimez le gestionnaire dans un bloc enfin (nécessaire au cas où le gestionnaire lèverait une exception):
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
EventHandler<WalkerStepEventArgs> handler = (sender, e) =>
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.FoundStep += handler;
try
{
this.Start();
}
finally
{
this.FoundStep -= handler;
}
return retval;
}
Avec C # 7.0+, vous pouvez remplacer le délégué anonyme par une fonction locale, obtenant le même effet:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
var retval = new List<IWFResourceInstance>();
void Handler(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
}
FoundStep += Handler;
try
{
this.Start();
}
finally
{
FoundStep -= Handler;
}
return retval;
}
Vous trouverez ci-dessous une approche sur la façon de désinscrire un événement dans une méthode anonyme:
DispatcherTimer _timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(1000);
EventHandler handler = null;
int i = 0;
_timer.Tick += handler = new EventHandler(delegate(object s, EventArgs ev)
{
i++;
if(i==10)
_timer.Tick -= handler;
});
_timer.Start();
Non, il ne sera pas supprimé automatiquement. En ce sens, il n'y a pas de différence entre une méthode anonyme et une méthode "normale". Si vous le souhaitez, vous devez vous désabonner manuellement de l'événement.
En fait, il va capturer d'autres variables (par exemple res
dans votre exemple) et les garder en vie (empêche le garbage collector de les collecter) aussi.
Lorsque vous utilisez un délégué anonyme (ou une expression lambda) pour vous abonner à un événement, vous ne pouvez pas vous désabonner facilement de cet événement ultérieurement. Un gestionnaire d'événements n'est jamais automatiquement désabonné.
Si vous regardez votre code, même si vous déclarez et vous abonnez à l'événement dans une fonction, l'événement auquel vous vous abonnez est dans la classe, donc une fois abonné, il sera toujours abonné même après la fin de la fonction. L'autre chose importante à réaliser est que chaque fois que cette fonction est appelée, elle s'abonne à nouveau à l'événement. Ceci est parfaitement légal car les événements sont essentiellement des délégués de multidiffusion et autorisent plusieurs abonnés. (Cela peut ou non être votre intention.)
Pour vous désinscrire du délégué avant de quitter la fonction, vous devez stocker le délégué anonyme dans une variable de délégué et ajouter le délégué à l'événement. Vous devez ensuite pouvoir supprimer le délégué de l'événement avant la fermeture de la fonction.
Pour ces raisons, si vous devez vous désinscrire de l'événement à un moment ultérieur, il n'est pas recommandé d'utiliser des délégués anonymes. Voir Comment: vous abonner à des événements et vous y désabonner (Guide de programmation C #) (en particulier la section intitulée "Pour vous abonner à des événements en utilisant une méthode anonyme ").