¿Tiene .NET un EventArgs <T> integrado?

84

Me estoy preparando para crear una clase EventArgs genérica para argumentos de eventos que llevan un solo argumento:

public class EventArg<T> : EventArgs
{
    // Property variable
    private readonly T p_EventData;

    // Constructor
    public EventArg(T data)
    {
        p_EventData = data;
    }

    // Property for EventArgs argument
    public T Data
    {
        get { return p_EventData; }
    }
}

Antes de hacer eso, ¿C # tiene la misma característica integrada en el lenguaje? Creo recordar haberme encontrado con algo así cuando salió C # 2.0, pero ahora no puedo encontrarlo.

O para decirlo de otra manera, ¿tengo que crear mi propia clase genérica EventArgs, o C # proporciona una? Gracias por tu ayuda.

David Veeneman
fuente
9
Puede que lo hayas vistoEventhandler<T>
Henk Holterman
1
Es posible que lo haya visto EventArgs<T>en código basado en CAB / SCSF. Es bastante común en aplicaciones CAB / SCSF. Aunque no es parte del marco, no es un EventArgs <T> aplicación.
Shaun Wilson

Respuestas:

66

No. Probablemente estaba pensando EventHandler<T>, lo que le permite definir el delegado para cualquier tipo específico de EventArgs.

Sin EventArgs<T>embargo, personalmente no creo que encaje tan bien. La información utilizada como "carga útil" en los argumentos de evento debería ser, en mi opinión, una clase personalizada para que su uso y las propiedades esperadas sean muy claras. El uso de una clase genérica evitará que pueda poner nombres significativos en su lugar. (¿Qué representa "Datos"?)

Reed Copsey
fuente
50
En aplicaciones centradas en datos, similares a MPI, es bastante común ver un EventArgs <T> en su lugar para el procesamiento de datos, de modo que los desarrolladores puedan aprovechar un sistema integrado de suscripción / registro con seguridad de tipos (Eventos y delegados .NET), ya que no tiene absolutamente ningún sentido crear subclases de EventArgs solo para transportar datos. Si su intención es transportar datos, podría decirse que tiene más sentido definir un EventArgs <T> que puede subclase para usos discretos SIN tener en cuenta los datos que se transportan. TL: DR Esta primera parte de esta respuesta es fáctica y precisa, la segunda parte es subjetiva / opinión.
Shaun Wilson
1
Supongo que tienes razón ... resiste la pereza que me trajo aquí. Es como cuando los desarrolladores perezosos usan Tuple <,>. Cosas terribles.
CRice
Un buen punto, pero esto esencialmente haría lo mismo que hizo Microsoft cuando agregaron la propiedad Etiqueta a las clases de Controles. Por supuesto, solo porque MS lo hizo, no lo hace bien.
Ken Richards
1
Estoy de acuerdo con el primer comentarista, toda la segunda mitad de esta respuesta es una opinión subjetiva / código-religión que no fue constructiva. :(
BrainSlugs83
5
¿Cómo EventHandler <Customer> o EventHandler <Order> transmiten menos información que CustomerEventHandler o OrderEventHandler ?
Quarkly
33

Debo decir que no entiendo a todos los 'puristas' aquí. es decir, si ya tiene una clase de bolsa definida, que tiene todos los detalles, propiedades, etc., ¿por qué el truco crea una clase adicional innecesaria solo para poder seguir el mecanismo de eventos / argumentos, estilo de firma? La cosa es que, no todo lo que está en .NET, o que 'falta en' para el caso, es 'bueno': MS se ha 'corrigido' a sí mismo durante años ... Yo diría que simplemente vaya y cree uno, como lo hice yo porque lo necesitaba así y me ahorré mucho tiempo

NSGaga-principalmente-inactivo
fuente
3
En este caso, el punto 'purista' es dejar la intención lo más clara posible. En una aplicación de producción, tengo docenas de estas clases EventArgs. Dentro de un año, será más fácil entender lo que hice si sigo los consejos de Reed y creo una clase EventArgs personalizada.
David Veeneman
9
no quise etiquetar a nadie :) el punto está en el 'genérico' en el evento - si solo necesitas una docena de eventos diferentes, ok. Pero si no conoce la naturaleza de la T de antemano, eso solo se conoce en tiempo de ejecución, bueno, necesita un evento genérico. Entonces, si tiene una aplicación que es una buena parte que trata con genéricos, un número arbitrario de tipos, desconocido, entonces también necesita eventos genéricos. o es decir, no hay una solución clara para cada problema, la regla general es solo una regla general, y eso es lo que quiero decir con puristas, cada solución es diferente, debe sopesar las cosas, los pros y los contras
NSGaga, principalmente. inactivo
2
El diseño no es blanco y negro, así que suelo estar de acuerdo con NSGaga aquí. A veces, "rápido y sucio" es apropiado. El lenguaje debe ser rico en funciones para adaptarse a la mayoría de los casos de uso. El desarrollador debe decidir qué es lo apropiado. La última vez que MS intentó forzar un diseño "bueno" limitando el lenguaje fue WPF cuando intentaron forzar el uso de XAML al perjudicar gravemente la API .NET, y fue terrible.
Robear
9

Existe. Al menos, lo hace ahora.

Puede encontrar DataEventArgs<TData>en algunos ensamblados / espacios de nombres diferentes de Microsoft, por ejemplo, Microsoft.Practices.Prism.Events . Sin embargo, estos son espacios de nombres que puede que no le resulte natural incluir en su proyecto, por lo que puede usar su propia implementación.

Ulf Åkerstedt
fuente
He estado tratando de encontrar recomendaciones y consideraciones sobre cuándo y por qué usar una clase EventArgs tan genérica. Ver también: stackoverflow.com/questions/15766219/…
Ulf Åkerstedt
Estos son algunos aspectos a tener en cuenta al decidir utilizar un EventArgs genérico: stackoverflow.com/questions/129453/…
Ulf Åkerstedt
7

En caso de que elija no usar Prism , pero aún así le gustaría probar un enfoque genérico de EventArgs .

public class GenericEventArgs<T> : EventArgs
{
    public T EventData { get; private set; }

    public GenericEventArgs(T EventData)
    {
        this.EventData = EventData;
    }
}

// Utilice el siguiente código de muestra para declarar el evento ObjAdded

public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;

// Usa el siguiente código de muestra para generar el evento ObjAdded

private void OnObjAdded(TargetObjType TargetObj)
{
    if (ObjAdded!= null)
    {
        ObjAdded.Invoke(this, new GenericEventArgs<TargetObjType>(TargetObj));
    }
}

// Y finalmente puedes suscribirte a tu evento ObjAdded

SubscriberObj.ObjAdded +=  (object sender, GenericEventArgs<TargetObjType> e) =>
{
    // Here you can explore your e.EventData properties
};
Julio Nobre
fuente
3

NO HAY ARGS GENÉRICOS INTEGRADOS. Si sigue el patrón Microsoft manejador de sucesos, a continuación, a implementar sus derivados EventArgs como usted sugiere: public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.

SIN EMBARGO, si la guía de estilo de su equipo acepta una simplificación, su proyecto puede utilizar eventos ligeros, como este:

public event Action<object, string> MyStringChanged;

uso:

// How to rise
private void OnMyStringChanged(string e)
{
    Action<object, string> handler = MyStringChanged;    // thread safeness
    if (handler != null)
    {
        handler(this, e);
    }
}

// How to handle
myObject.MyStringChanged += (sender, e) => Console.WriteLine(e);

Por lo general, los proyectos de PoC utilizan el último enfoque. Sin embargo, en aplicaciones profesionales, tenga en cuenta la justificación de policía FX # CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx

epoxi
fuente
1

El problema con un tipo genérico es que incluso si DerivedType hereda de BaseType, EventArgs (DerivedType) no heredaría de EventArgs (BaseType). El uso de EventArgs (BaseType) evitaría el uso posterior de una versión derivada del tipo.

Super gato
fuente
2
Esto es evidentemente falso. consulte "Covarianza y contravarianza en genéricos - Microsoft.com" msdn.microsoft.com/en-us/library/dd799517.aspx
Shaun Wilson
1
@ShaunWilson: ¿Qué aspecto es falso? Se podría definir una interfaz covariante IEventArgs, pero las únicas clases que pueden ser genéricas con respecto a los parámetros de tipo genérico son los delegados a los que no se alimentará Delegate.Combine. Los delegados que se utilizarán con Delegate.Combineno deben ser covariantes, ya que se puede almacenar, por ejemplo, an Action<DerivedType>en un campo de tipo Action<BaseType>, pero un intento posterior Combinecon una instancia de Action<BaseType>fallará.
supercat
-4

La razón por la que esto no existe es porque lo que terminaría sucediendo es que lo implementas, y luego, cuando vayas a completar la T, debes crear una clase con propiedades inequívocas fuertemente tipadas que actúe como la bolsa de datos para tu evento arg, pero a la mitad de la implementación, se da cuenta de que no hay razón para que no haga que la clase herede de EventArgs y la llame buena.

A menos que solo desee una cadena o algo igualmente básico para su bolsa de datos, en cuyo caso probablemente haya clases EventArgs estándar en .NET que están destinadas a servir cualquier propósito simple al que se esté dirigiendo.

Jimmy Hoffa
fuente
-1. Tengo EXACTAMENTE esta situación ahora, y mi carga útil sería un objeto inmutable que es un "mensaje" proveniente de un autobús ... y también se encuentra en otros lugares. El EventArgs personalizado .... crea una clase redundante aquí. Inusual, pero la aplicación lo es.
TomTom