Question

Y a-t-il un avantage à attacher/détacher dynamiquement des gestionnaires d’événements ?

Le détachement manuel des gestionnaires permettrait-il de garantir qu'il ne reste plus de référence à un objet supprimé ?

Était-ce utile?

La solution

Il ne s'agit pas d'utiliser AddHandler ou Handles.

Si vous craignez que la référence à votre gestionnaire d'événements interfère avec le garbage collection, vous devez utiliser RemoveHandler, quelle que soit la manière dont le gestionnaire a été attaché.Dans la méthode Dispose du formulaire ou du contrôle, supprimez tous les gestionnaires.

J'ai eu des situations dans les applications Windows Forms (.NET 1.1 jours) où un gestionnaire d'événements serait appelé sur des contrôles qui n'avaient aucune autre référence à eux (et qui, à toutes fins utiles, étaient morts et j'aurais pensé qu'ils avaient été GC) -- extrêmement difficile à déboguer.

J'utiliserais RemoveHandler pour supprimer les gestionnaires des contrôles que vous n'allez pas réutiliser.

Autres conseils

Je suis presque sûr que le Handles La clause n'est qu'un sucre syntaxique et insère un AddHandler déclaration dans votre constructeur.J'ai testé en utilisant ce code et désactivé le framework d'application afin que le constructeur n'ait pas de choses supplémentaires :


Public Class Form1

    Public Sub New()
        ' This call is required by the Windows Form Designer. '
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call. '
        AddHandler Me.Load, AddressOf Form1_Load
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim breakpoint As Integer = 4
    End Sub
End Class

L'IL s'est terminé ainsi :

  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
  IL_0007:  nop
  IL_0008:  ldarg.0
  IL_0009:  ldarg.0
  IL_000a:  dup
  IL_000b:  ldvirtftn  instance void WindowsApplication1.Form1::Form1_Load(object,
                                                                           class [mscorlib]System.EventArgs)
  IL_0011:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object,
                                                                          native int)
  IL_0016:  call       instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)

 '... lots of lines here '

  IL_0047:  ldarg.0
  IL_0048:  callvirt   instance void WindowsApplication1.Form1::InitializeComponent()
  IL_004d:  nop
  IL_004e:  ldarg.0
  IL_004f:  ldarg.0
  IL_0050:  dup
  IL_0051:  ldvirtftn  instance void WindowsApplication1.Form1::Form1_Load(object,
                                                                           class [mscorlib]System.EventArgs)
  IL_0057:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object,
                                                                          native int)
  IL_005c:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)
  IL_0061:  nop
  IL_0062:  nop
  IL_0063:  ret
} // end of method Form1::.ctor

Notez deux blocs de code identiques autour de IL_000b et IL_0051.Je pense que c'est juste du sucre syntaxique.

Déclarer un champ comme WithEvents le compilateur générera automatiquement une propriété portant ce nom.Le getter renvoie la valeur d'un champ de sauvegarde.Le passeur est un peu plus compliqué.Il vérifie d'abord si le champ de sauvegarde a déjà la valeur correcte.Si c'est le cas, il sort.Sinon, si le champ de sauvegarde n'est pas nul, il émet des requêtes « RemoveHandler » pour tous ses événements vers l'objet identifié par le champ de sauvegarde.Ensuite, que le champ de sauvegarde soit non nul ou non, il le définit égal à la valeur demandée.Enfin, si la nouvelle valeur est non nulle, que l'ancienne l'était ou non, la propriété émet des requêtes "AddHandler" pour tous ses événements vers l'objet identifié par la nouvelle valeur.

À condition que l'on définisse tous les membres WithEvents d'un objet sur Nothing avant de l'abandonner et d'éviter de manipuler les membres WithEvents dans plusieurs threads, le code d'événement généré automatiquement ne fuira pas.

Je trouve que l'attachement/détachement dynamique des gestionnaires d'événements n'est utile que lorsqu'un objet de longue durée expose des événements qui sont consommés par de nombreux objets de courte durée.Dans la plupart des autres cas, les deux objets sont éliminés à peu près en même temps et le CLR fait un travail de nettoyage suffisant tout seul.

J'attache manuellement des gestionnaires lorsque je crée manuellement des contrôles (par exemple, en créant dynamiquement une TextBox pour chaque enregistrement de base de données).Je détache manuellement les gestionnaires lorsqu'ils gèrent des choses que je ne suis pas encore prêt à gérer (peut-être parce que j'utilise les mauvais événements ?:) )

Détacher manuellement un événement peut être important pour éviter les fuites de mémoire :l'objet qui se connecte à un événement déclenché par un autre objet ne sera pas récupéré tant que l'objet qui déclenche l'événement ne sera pas récupéré.En d’autres termes, un « événement-raiser » a une forte référence à tous les « événements-auditeurs » qui lui sont connectés.

La plupart du temps, le framework s’en charge pour vous.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top