2010-07-10 20 views
8

Busqué en los archivos y encontré muchas preguntas sobre qué es el remitente y por qué debería usar el patrón, pero no vi nada sobre un evento personalizado y tipo si es remitente.Crear eventos personalizados: ¿remitente de objeto o remitente con tipo?

Digamos que estoy creando una clase personalizada llamada Subscription e implementa ISubscription y tengo algunos eventos args llamados SubscriptionEventArgs. Si la Suscripción tuvo un evento llamado Modificado, ¿qué pasa con la firma del evento Modificada (ISubscription remitente, SubscriptionEventArgs e)?

un poco de código para ayudar a impulsar la pregunta:

public class SubscriptionEventArgs : EventArgs 
{ 
    // guts of event args go here 
} 

public interface ISubscription 
{ 
    event Action<ISubscription, SubscriptionEventArgs> Changed; 
} 

public class Subscription : ISubscription 
{ 
    public event Action<ISubscription, SubscriptionEventArgs> Changed; 

    private void OnChanged(SubscriptionEventArgs e) 
    { 
     if (Changed!= null) 
     { 
      Changed(this, e); 
     } 
    } 
} 

Si sólo desprecian el uso de la acción en lugar de "manejador de sucesos", entonces se podría hacer lo mismo, pero con una costumbre genérico "manejador de sucesos".

public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e); 

public class SubscriptionEventArgs : EventArgs 
{ 
    // guts of event args go here 
} 

public interface ISubscription 
{ 
    event EventHandler<ISubscription, SubscriptionEventArgs> Changed; 
} 

public class Subscription : ISubscription 
{ 
    public event EventHandler<ISubscription, SubscriptionEventArgs> Changed; 

    private void OnChanged(SubscriptionEventArgs e) 
    { 
     if (Changed!= null) 
     { 
      Changed(this, e); 
     } 
    } 
} 

En respuesta a la solicitud de Hans para un controlador de eventos de muestra:

public class SubscriptionCollection 
{ 
    // what is actually holding the subscriptions is not really relevant to the question 
    private List<ISubscription> _subscriptions; 

    public SubscriptionCollection() 
    { 
     _subscriptions = new List<ISubscription>(); 
    } 

    public void Add(ISubscription subscription) 
    { 
     subscription.Changed += new EventHandler<ISubscription, SubscriptionEventArgs>(Subscription_Changed); 
     _subscriptions.Add(subscription); 
    } 

    private void Subscription_Changed(ISubscription sender, SubscriptionEventArgs e) 
    { 
     // Now when the subscription changed event is being handled by the collection 
     // I don't have to look up the subscription in the list by some key and I don't 
     // have to cast sender to the correct type because the event handler was typed 
     // correctly from the beginning. 
    } 
} 

La búsqueda de la suscripción en la lista puede parecer trivial, pero lo que si estoy trabajando con grandes conjuntos de datos y nuevos volúmenes de datos llegan a la aplicación a través de una transmisión en tiempo real. El costo de tener que parar y obtener una referencia de una lista o seguir los pasos de un casting no tiene sentido. Nos dieron genéricos en 2.0 para resolver ese problema, así que no entiendo por qué no obtuvimos un gestor de eventos genérico también y esto me llevó a preguntar qué pasa con un controlador de eventos genérico.

+0

me gustaría el segundo bloque mucho más si se agregó un "donde TEventArgs: EventArgs". –

+0

Solo un consejo, pero si usa IObservable en lugar de ISubscription para su tipo de interfaz, creo que estaría siguiendo un patrón de diseño nombrando un poco mejor, y puede ser un poco más claro a simple vista lo que está sucediendo. –

Respuesta

0

En realidad estoy bastante confundido por qué, cuando se diseña el .Net Framework v2, MS no proporcionó una EventHandler sólo la forma en que usted describe - con el TSender y TEventArgs ya que ambos argumentos genéricos. (En v1 y v1.1, dado que no tenían genéricos, entiendo completamente por qué no crearon miles de tipos de delegados adicionales para manejar todos los eventos posibles). Si mal no recuerdo, aún puede usar un manejador generalizado. para escuchar un caso más específico:

public event EventHandler<Button, MouseDownEventArgs> MouseDown; 

private void ObservingMethod(object sender, EventArgs e) { } 

MouseDown += new EventHandler<Button, MouseDownEventArgs>(ObservingMethod); 

Puesto que no se está exponiendo al observador a lo observable, no veo cómo esto podría ser un problema; solo está impidiendo la necesidad de hacer una verificación de tipo 'por las dudas' una vez que llega al manejador de eventos. Creo que sería una práctica fantástica, aunque un poco no estándar, ya que MS decidió no incluirla.

Como se señaló en mi comentario anterior, yo preferiría ver la siguiente definición del manejador de sucesos, para que realmente siempre se puede utilizar un método de control muy generalizado, como mi ejemplo de código:

public delegate void EventHandler<TSender, TEventArgs>(TSender sender, TEventArgs e) 
    where TEventArgs : EventArgs; 
+0

Probablemente porque la mayoría de esos eventos se declaran en una clase base (Control - ButtonBase - ...) y, por lo tanto, no tendrían la clase Button como remitente. (y aún no hay covarianza;) – Stormenet

+0

Eso es justo, pero incluso usar el objeto más restrictivo, incluso si fuera una clase base abstracta o incluso una interfaz que conociera, sería útil. Por ejemplo, tener acceso rápido sin conversión para una llamada de CaptureMouse desde un evento MouseDown. Y, dado que el ajuste explícito de delegados funciona (como se indicó anteriormente, sin genéricos), aún podríamos usar un controlador de eventos generalizado. –

Cuestiones relacionadas