Frage

Ich suche für einige Hinweise auf die Umsetzung Benutzerdefinierte Ereignisse in VB.NET (Visual Studio 2008, .NET 3.5).

Ich weiß, dass „normale“ (nicht-custom) Event sind eigentlich Delegierten, so dass ich daran dachte Delegierten zu verwenden, wenn ein benutzerdefiniertes Ereignis zu implementieren. Auf der anderen Seite, Andrew Troelsen 's "Pro VB 2008 und .NET 3.5-Plattform" Buch verwendet Sammlung Typen in allen seinen Benutzerdefinierte Ereignisse Beispiele und Microsofts Beispielcodes , dass die Linie des Denkens entspricht.

Also meine Frage ist: Welche Überlegungen sollte ich haben, wenn ein Design über das andere Wahl? Was sind die Vor- und Nachteile für jeden Entwurf? Welche diese sieht etwa innere Umsetzung von „normalen“ Ereignissen?

Im Folgenden finden Sie ein Beispielcode demonstriert die beiden Designs.

Public Class SomeClass
    Private _SomeEventListeners As EventHandler
    Public Custom Event SomeEvent As EventHandler
        AddHandler(ByVal value As EventHandler)
            _SomeEventListeners = [Delegate].Combine(_SomeEventListeners, value)
        End AddHandler

        RemoveHandler(ByVal value As EventHandler)
            _SomeEventListeners = [Delegate].Remove(_SomeEventListeners, value)
        End RemoveHandler

        RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
            _SomeEventListeners.Invoke(sender, e)
        End RaiseEvent
    End Event

    Private _OtherEventListeners As New List(Of EventHandler)
    Public Custom Event OtherEvent As EventHandler
        AddHandler(ByVal value As EventHandler)
            _OtherEventListeners.Add(value)
        End AddHandler

        RemoveHandler(ByVal value As EventHandler)
            _OtherEventListeners.Remove(value)
        End RemoveHandler

        RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
            For Each handler In _OtherEventListeners
                handler(sender, e)
            Next
        End RaiseEvent
    End Event
End Class
War es hilfreich?

Lösung

würde ich sagen, die einfach Delegierten verwenden; einfach - es ist bereits (intern) eine Liste, so dass Sie Aufwand duplizieren, indem sie es in List<T> Verpackung. Sie haben auch den Aufwand für zusätzliche Liste Objekte und Arrays, die null sein könnte, so dass mehr Einfluss auf die Garbage Collection etc.

Auch wenn Sie tun, viel Dies betrachten EventHandlerList, die einen effizienten Zugriff auf spärlich Veranstaltungen bieten existiert - also dort, wo Sie viele Ereignisse verfügbar machen möchten, aber viele von ihnen können nicht zugeordnet werden.

Das erste Beispiel ist viel näher an „Standard“ Ereignisse (obwohl sie nicht zugewiesen / null Handler sehen möchten, wenn Invoke nennen, wie es null sein könnte). Außerdem ist zu beachten, dass einige Sprachen (ich weiß ehrlich nicht, was VB tut hier) gilt Synchronisation auf Ereignisse, aber in Wirklichkeit nur sehr wenige Ereignisse wirklich müssen Thread-sicher sein, so dass viel des Guten sein könnte.

Bearbeiten es tritt auch auf, dass es ein funktioneller Unterschied zwischen ihnen:

  • die Delegierten Ansatz behandelt verschiedene Instanzen mit der gleichen Zielmethode / Instanz als gleich (Ich glaube nicht, das List<T> wird)
  • doppelt Delegierten: Delegierten entfernt letzte zuerst; Liste entfernt frühest erst
  • Komposite: A, fügen B und entfernen (A + B) - mit einem Delegierten sollte null ergeben / leeren, aber die Liste Ansatz behält A und B (mit dem (A + B) entfernen Fehler zu finden alles)

Andere Tipps

Mit einer MulticastDelegate eine Liste der abonnierten Ereignisse zu halten, ist sicherlich ein praktikable Ansatz, aber nicht, den ich bin gespannt, besonders auf. Zum Hinzufügen oder ein Ereignis aus einem MulticastDelegate zu entfernen, muss man eines von zwei Dingen tun:

  1. Erwerben Sie eine Sperre, erstellen Sie einen neuen Delegierten von der alten, aber mit einem Ereignis hinzugefügt oder entfernt, den Delegaten Zeiger auf diesen Delegierten festgelegt, und lassen Sie dann die Sperre
  2. Kopieren Sie einen Verweis auf den alten delegieren, erstellen Sie einen neuen Delegierten, aber mit einem Ereignis hinzugefügt oder entfernt werden, verwenden Interlocked.CompareExchange den Verweis auf die neue zu speichern, wenn die alte unverändert ist, und beginnen alle über, wenn die CompareExchange fehlgeschlagen.

Der zweite Ansatz kann eine etwas bessere Leistung bieten, wenn es keine Konkurrenz gibt, kann aber schlecht durchführen, wenn viele Threads gleichzeitig hinzufügen oder löschen Ereignisse versuchen. Ein Vorteil des letzteren Ansatzes ist jedoch, dass es keine Gefahr eines Threads sterben, während eine Sperre hält.

Weder Ansatz scheint besonders sauber. Wenn man auf den Aufruf für alle Veranstaltungen plant, indem man einfach einen Delegaten aufrufen, kann das Ereignis-Aufruf Leistung Offset hinzufügen / entfernen Leistung. Auf der anderen Seite, wenn man Pläne GetInvocationList, um Wrap-Ereignis Anrufe in try / catch-Blöcken zu verwenden, kann man besser dran, einen nur mit (in geeigneter Weise verriegelt) Liste oder andere derartige Datenstruktur.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top