Pregunta

Estoy buscando algunos consejos sobre la implementación de eventos personalizados en VB.NET (Visual Studio 2008, .NET 3.5).

Yo sé que (no personalizados) Eventos "normales" son en realidad los delegados, así que estaba pensando en utilizar delegados en la aplicación de un evento personalizado. Por otro lado, Andrew Troelsen 's "Pro VB 2008 y .NET 3.5 Plataforma" libro utiliza tipos de recolección en todos sus ejemplos eventos personalizados, y códigos de ejemplo de Microsoft que coincida con la línea de pensamiento.

Así que mi pregunta es: ¿qué consideraciones debería tener al elegir un diseño sobre el otro? ¿Cuáles son los pros y los contras de cada diseño? ¿Cuál de estos se asemeja a la del centro de la realización de eventos "normales"?

A continuación se muestra un código de ejemplo que muestra los dos diseños.

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
¿Fue útil?

Solución

Yo diría utilizar el delegado sencilla; simplemente - es ya (internamente) una lista, por lo que está duplicando el esfuerzo envolviéndolo en List<T>. Usted también tiene la sobrecarga de objetos de la lista adicionales y matrices, que podría ser nula, por lo que más impacto en la recolección de basura, etc.

Además, si usted está haciendo lotes de esto, considere EventHandlerList, que existe para proporcionar un acceso eficaz a escasa eventos - es decir, en las que desea exponer a una gran cantidad de eventos, pero muchos de ellos pueden ser asignados.

El primer ejemplo es mucho más cerca de los acontecimientos "estándar" (aunque es posible que desee ver a los manipuladores sin asignar / nulos cuando se llama a Invoke, ya que podría ser nulo). Además, nota que algunos idiomas (honestamente no sabe lo que hace VB aquí) se aplica a la sincronización de eventos, pero en realidad muy pocos eventos realmente necesidad de ser flujos seguros, por lo que podría ser una exageración.

editar también ocurre que hay un funcional diferencia entre ellos:

  • el enfoque delegado golosinas diferentes instancias con el mismo método de destino / instancia como igual (no creo que la List<T> voluntad)
  • delegados duplicados: Elimina delegado pasado primero; Lista elimina más temprana primero
  • materiales compuestos: Añadir una, añadir B y remove (A + B) - con un delegado esta nula debe ceder / vacío, pero el enfoque de lista conservará A y B (con la A + B) remove (no encontrar nada)

Otros consejos

El uso de un MulticastDelegate para mantener una lista de eventos suscritas es sin duda un enfoque viable, pero no uno que estoy particularmente interesado en. Para añadir o eliminar un evento desde un MulticastDelegate, hay que hacer una de dos cosas:

  1. obtener un bloqueo, crear un nuevo delegado de la anterior, pero con un evento añadido o eliminado, establecer el puntero del delegado a que el delegado y, a continuación, liberar el bloqueo
  2. Copiar una referencia al antiguo delegado, crear un nuevo delegado de la misma, pero con un evento añadido o eliminado, utilice Interlocked.CompareExchange para almacenar la referencia a la nueva si el anterior no se ha modificado, y empezar todo de si el CompareExchange falló.

El último enfoque puede ofrecer un mejor rendimiento si no hay contención, pero puede realizar mal si muchos hilos están tratando al mismo tiempo de agregar o eventos eliminar. Una ventaja de este último enfoque, sin embargo, es que no hay peligro de un hilo de morir, mientras que mantiene un bloqueo.

Ni enfoque parece particularmente limpia. Si uno está planeando sobre la invocación de todos los eventos con sólo invocar un delegado, el rendimiento evento de invocación puede compensar el rendimiento de añadir / quitar. Por otro lado, si uno planea utilizar GetInvocationList fin de llamadas de eventos de envoltura en bloques try / catch, uno puede ser mejor simplemente usando una lista (adecuadamente bloqueado) u otra estructura de datos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top