.NET dispone di un EventArgs <T> integrato?


85

Mi sto preparando a creare una classe EventArgs generica per argomenti evento che contengono un singolo argomento:

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; }
    }
}

Prima di farlo, C # ha la stessa funzionalità incorporata nel linguaggio? Mi sembra di ricordare di essermi imbattuto in qualcosa del genere quando è uscito C # 2.0, ma ora non riesco a trovarlo.

O, in altre parole, devo creare la mia classe EventArgs generica o C # ne fornisce una? Grazie per l'aiuto.


9
Potresti aver vistoEventhandler<T>
Henk Holterman

1
Potresti aver visto EventArgs<T>nel codice basato su CAB / SCSF. È abbastanza comune nelle applicazioni CAB / SCSF. Anche se non è parte del quadro, non v'è un EventArgs <T> implementazione.
Shaun Wilson

Risposte:


68

No. Probabilmente stavi pensando EventHandler<T>, che ti consente di definire il delegato per qualsiasi tipo specifico di EventArgs.

Personalmente, però, non credo che EventArgs<T>sia così buono. Le informazioni utilizzate come "payload" nell'evento args dovrebbero essere, a mio parere, una classe personalizzata per rendere molto chiari il suo utilizzo e le proprietà attese. L'uso di una classe generica ti impedirà di inserire nomi significativi. (Cosa rappresenta "Dati"?)


52
Nelle applicazioni incentrate sui dati e simili a MPI è abbastanza comune vedere un EventArgs <T> in atto per l'elaborazione dei dati in modo che gli sviluppatori possano sfruttare un sistema di sottoscrizione / registrazione integrato e indipendente dai tipi (.NET Events and Delegates), poiché non ha assolutamente senso creare sottoclassi EventArgs solo per trasportare i dati. Se il tuo intento è quello di trasportare i dati, probabilmente ha più senso definire un EventArgs <T> che puoi sottoclasse per usi discreti SENZA tenere conto dei dati trasportati. TL: DR Questa prima parte di questa risposta è fattiva e accurata, la seconda parte è soggettiva / opinione.
Shaun Wilson

1
Suppongo che tu abbia ragione ... resisti alla pigrizia che mi ha portato qui. È come quando gli sviluppatori pigri usano Tuple <,>. Roba terribile.
CRice

Un buon punto, ma essenzialmente farebbe la stessa cosa di Microsoft quando ha aggiunto la proprietà Tag alle classi Controls. Certo, solo perché l'ha fatto la SM, non lo fa bene.
Ken Richards

1
Sono d'accordo con il primo commentatore, l'intera seconda metà di questa risposta è un'opinione soggettiva / religione in codice che non è stata costruttiva. :(
BrainSlugs83

6
In che modo EventHandler <Customer> o EventHandler <Order> trasmettono meno informazioni rispetto a CustomerEventHandler o OrderEventHandler ?
Quarkly

33

Devo dire che non capisco tutti i "puristi" qui. cioè, se hai già una classe bag definita - che ha tutte le specifiche, le proprietà ecc. - perché l'hack crea una classe extra non necessaria solo per poter seguire il meccanismo degli eventi / argomenti, lo stile della firma? il fatto è che - non tutto ciò che è in .NET - o che è "mancante da" per quella materia - è "buono" - la SM si sta "correggendo" da sola per anni ... Direi di andare e crearne uno - come ho fatto io - perché ne avevo bisogno proprio così - e mi ha fatto risparmiare un sacco di tempo,


3
In questo caso, il punto dei "puristi" è rendere l'intenzione il più chiara possibile. In un'app di produzione, ho dozzine di queste classi EventArgs. Tra un anno sarà più facile capire cosa ho fatto se seguo i consigli di Reed e creo una classe EventArgs personalizzata.
David Veeneman

9
non volevo etichettare nessuno :) il punto è nel "generico" nell'evento - se hai solo bisogno di una dozzina di eventi diversi, ok. Ma se non conosci in anticipo la natura della T - che è nota solo in fase di esecuzione - beh, ti serve un evento generico. Quindi, se hai un'app che è una buona parte che si occupa di generici, un numero arbitrario di tipi, sconosciuto, allora hai anche bisogno di eventi generici. o cioè non c'è una soluzione pulita per ogni problema, la regola empirica è solo una regola empirica - ed è quello che intendevo per puristi, ogni soluzione è diversa, devi valutare le cose, i pro ei contro
NSGaga-principalmente- inattivo

2
Il design non è in bianco e nero, quindi tendo ad essere d'accordo con NSGaga qui. A volte, "veloce e sporco" è appropriato. Il linguaggio dovrebbe essere ricco di funzionalità per adattarsi alla maggior parte dei casi d'uso. Spetta allo sviluppatore decidere cosa è appropriato. L'ultima volta che MS ha tentato di forzare un design "buono" limitando il linguaggio è stato WPF quando hanno tentato di forzare l'uso di XAML ostacolando gravemente l'API .NET, ed è stato terribile.
Robear

9

Esiste. Almeno adesso lo fa.

È possibile trovare DataEventArgs<TData>in alcuni diversi assembly / spazi dei nomi Microsoft , ad esempio Microsoft.Practices.Prism.Events . Tuttavia questi sono spazi dei nomi che potresti non trovare naturale includere nel tuo progetto, quindi potresti semplicemente usare la tua implementazione.


Ho cercato di trovare consigli e considerazioni su quando e perché utilizzare una classe EventArgs così generica. Vedi anche: stackoverflow.com/questions/15766219/...
Ulf Åkerstedt

Qui ci sono alcuni aspetti di stare attenti quando si decide di utilizzare un EventArgs generici: stackoverflow.com/questions/129453/...
Ulf Åkerstedt

7

Nel caso in cui scegli di non utilizzare Prism , ma desideri comunque provare un approccio EventArgs generico .

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

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

// Utilizzare il seguente codice di esempio per dichiarare l' evento ObjAdded

public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;

// Utilizzare il seguente codice di esempio per generare l' evento ObjAdded

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

// E finalmente puoi iscriverti al tuo evento ObjAdded

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

3

NON CI SONO ARG GENERICI INTEGRATI. Se si seguono modello Microsoft EventHandler, quindi di implementare i tuoi EventArgs derivati come da te suggerito: public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.

TUTTAVIA, se la guida di stile del tuo team accetta una semplificazione, il tuo progetto può utilizzare eventi leggeri, come questo:

public event Action<object, string> MyStringChanged;

utilizzo:

// 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);

Di solito i progetti PoC utilizzano quest'ultimo approccio. Nelle applicazioni professionali, tuttavia, tieni presente la giustificazione del poliziotto FX # CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx


1

Il problema con un tipo generico è che anche se DerivedType eredita da BaseType, EventArgs (DerivedType) non erediterà da EventArgs (BaseType). L'utilizzo di EventArgs (BaseType) impedirebbe quindi l'utilizzo successivo di una versione derivata del tipo.


2
Questo è palesemente falso. vedere "Covarianza e controvarianza nei generici - Microsoft.com" msdn.microsoft.com/en-us/library/dd799517.aspx
Shaun Wilson

1
@ShaunWilson: quale aspetto è falso? Si potrebbe definire un'interfaccia covariante IEventArgs, ma le uniche classi che possono essere generiche per quanto riguarda i parametri di tipo generico sono i delegati a cui non verranno forniti Delegate.Combine. I delegati che verranno usati con Delegate.Combinenon dovrebbero essere covarianti, poiché si può memorizzare, ad esempio, an Action<DerivedType>in un campo di tipo Action<BaseType>, ma un tentativo successivo Combinecon un'istanza di Action<BaseType>fallirà.
supercat

-4

Il motivo per cui questo non esiste è perché ciò che finirebbe per accadere è che tu lo implementi, e poi quando vai a riempire la T dovresti creare una classe con proprietà univoche fortemente tipizzate che funge da contenitore di dati per il tuo evento arg, ma a metà dell'implementazione ti rendi conto che non c'è motivo per cui non fai semplicemente in modo che quella classe erediti da EventArgs e la chiami buona.

A meno che tu non voglia solo una stringa o qualcosa di simile di base per la tua borsa di dati, nel qual caso ci sono probabilmente classi EventArgs standard in .NET che hanno lo scopo di servire qualunque semplice scopo tu stia ottenendo.


-1. Ho ESATTAMENTE questa situazione adesso, e il mio carico utile sarebbe un oggetto immutabile che è un "messaggio" proveniente da un autobus ... ed è utilizzato anche in altri posti. EventArgs .... personalizzato crea qui una classe ridondante. Insolito, ma l'applicazione è così.
TomTom
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.