Domanda

Sto cercando alcune indicazioni su attuazione Eventi Personalizzati in VB.NET (Visual Studio 2008, .NET 3.5).

So che "normali" (non personalizzati) Gli eventi sono in realtà delegati, così ho pensato di usare delegati in sede di attuazione di un evento personalizzato. D'altra parte, Andrew Troelsen 's "Pro VB 2008 e .NET 3.5 Platform" libro usa tipi collezione in tutti i suoi personalizzati Eventi esempi, e codici di esempio di Microsoft corrispondere a quella linea di pensiero.

Quindi la mia domanda è: quali considerazioni dovrei avere quando si sceglie un disegno sopra l'altro? Quali sono i pro ei contro per ogni disegno? Quale di questi assomiglia al interno-realizzazione di eventi "normali"?

Di seguito è riportato un codice di esempio che dimostra i due disegni.

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
È stato utile?

Soluzione

direi utilizzare il semplice delegato; semplicemente - è già (internamente) una lista, in modo da sta duplicando sforzo avvolgendolo in List<T>. Hai anche il sovraccarico di oggetti lista extra e gli array, che potrebbe essere nullo, quindi più impatto sulla raccolta dei rifiuti, ecc.

Inoltre, se si sta facendo un sacco di questo, si consideri EventHandlerList, che esiste per fornire un accesso efficiente al sparse eventi - vale a dire in cui si desidera esporre un sacco di eventi, ma molti di loro possono essere assegnati.

Il primo esempio è molto più vicino agli eventi "standard" (anche se si potrebbe desiderare di guardare per i gestori non assegnato / null quando si chiama Invoke, come potrebbe essere nullo). Inoltre, nota che alcune lingue (io onestamente non so che cosa VB fa qui) si applica la sincronizzazione di eventi, ma in realtà molto pochi eventi davvero ha bisogno di essere thread-safe, in modo che potrebbe essere eccessivo.

modifica si verifica anche che c'è un funzionale differenza tra di loro:

  • l'approccio delegato ossequi diverse istanze con lo stesso metodo di destinazione / istanza come uguali (non credo che il List<T> sarà)
  • delegati duplicati: rimuove delegato lo scorso primo; Lista rimuove prima prima
  • compositi: aggiungere A, aggiungere B, e rimuovere (A + B) - con un delegato questo dovrebbe produrre null / vuoto, ma l'approccio lista manterrà A e B (con la A + B) Rimuovere (non riuscendo a trovare nulla)

Altri suggerimenti

Utilizzo di un MulticastDelegate di tenere un elenco degli eventi sottoscritti è certamente un approccio praticabile, ma non uno Sono particolarmente appassionato. Per aggiungere o rimuovere un evento da un MulticastDelegate, si deve fare una delle due cose:

  1. acquisire un blocco, creare un nuovo delegato da quello vecchio, ma con un evento aggiunti o rimossi, impostare il puntatore delegato a quella delegato e quindi rilasciare il blocco
  2. Copia un riferimento al vecchio delegato, creare un nuovo delegato da esso, ma con un evento aggiunti o rimossi, utilizzare Interlocked.CompareExchange per memorizzare il riferimento al nuovo se quello vecchio è immutato, e ricominciare tutto da se il CompareExchange non è riuscita.

Il secondo approccio può offrire prestazioni leggermente migliori se non c'è conflitto, ma può eseguire male se molti thread simultaneamente cercando di aggiungere o rimuovere gli eventi. Un vantaggio di quest'ultimo approccio, però, è che non c'è pericolo di un filo di morire mentre si tiene un blocco.

Nessuno dei due approcci sembra particolarmente pulito. Se si sta progettando su come richiamare tutti gli eventi, semplicemente invocando un delegato, la performance-evento invocazione può compensare le prestazioni Aggiungi / Rimuovi. D'altra parte, se si prevede di utilizzare GetInvocationList in modo da chiamate di eventi avvolgere in blocchi try / catch, si può essere meglio solo con un (opportunamente bloccato) elenco o altro tale struttura di dati.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top