2010-07-22 2 views
74

io sono sempre pronto a creare una classe EventArgs generico per argomenti di eventi che portano un singolo argomento:.NET ha un EventArgs integrato <T>?

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 lo faccio, vuol C# hanno la stessa caratteristica integrato nel linguaggio? Mi sembra di ricordare di aver trovato qualcosa di simile quando è uscito C# 2.0, ma ora non riesco a trovarlo.

O per dirla in un altro modo, devo creare la mia classe EventArgs generica o C# ne fornisce una? Grazie per l'aiuto.

+8

Potreste aver visto '' EventHandler

+1

Potreste aver visto '' 'EventArgs ' '' in CAB/code SCSF-based. È abbastanza comune nelle applicazioni CAB/SCSF. Anche se non fa parte del framework, * esiste * una implementazione di EventArgs . –

risposta

61

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

Personalmente non ritengo che lo standard EventArgs<T> sia abbastanza buono. Le informazioni utilizzate come "payload" nell'argomento dell'evento dovrebbero essere, a mio avviso, una classe personalizzata per rendere molto chiaro l'utilizzo e le proprietà previste. L'utilizzo di una classe generica ti impedirà di mettere in campo nomi significativi. (Che cosa significa "Dati")

+39

In applicazioni incentrate sui dati, simili a MPI, è abbastanza comune vedere un EventArgs per l'elaborazione dei dati in modo che gli sviluppatori possano sfruttare un sistema di sottoscrizione/registrazione integrato sicuro per il tipo (Eventi e delegati .NET), come non ha assolutamente senso creare sottoclassi di EventArgs solo per il trasporto dei dati. Se il tuo intento è quello di trasportare dati, probabilmente ha più senso definire un EventArgs che puoi creare in sottoclassi per usi discreti SENZA riguardo per i dati trasportati. TL: DR Questa prima parte di questa risposta è fattiva e accurata, la seconda parte è soggettiva/opinione. –

+1

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

+0

Un buon punto, ma questo essenzialmente farebbe la stessa cosa che ha fatto Microsoft quando hanno aggiunto la proprietà Tag alle classi Controls. Certo, solo coz 'MS l'ha fatto, non è giusto. –

-4

La ragione per cui questo non esiste è perché ciò che accadrebbe è implementarlo, e poi quando si va a compilare il T si dovrebbe creare una classe con caratteri fortemente non ambigui le proprietà che fungono da sacchetto dati per il tuo evento arg, ma a metà strada dall'implementazione ti rendi conto che non c'è ragione per cui non ti limiti a far ereditare quella classe da EventArgs e chiamarla buona.

A meno che non si desideri semplicemente una stringa o qualcosa di simile di base per la propria borsa dati, nel qual caso ci sono probabilmente le classi EventArgs standard in .NET che sono pensate per servire a qualsiasi scopo semplice si sta ricevendo.

+0

-1. Ho ESATTAMENTE questa sitaution ora, e il mio carico utile sarebbe un oggetto immutabile che è un "messaggio" proveniente da un autobus ... e che si trova anche in altri luoghi. L'EventArgs personalizzato .... crea una classe ridondante qui. Insolito, ma l'applicazione è così. – TomTom

1

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

+2

Questo è chiaramente falso. vedere "Covarianza e controvarianza in Generics - Microsoft.com" http://msdn.microsoft.com/en-us/library/dd799517.aspx –

+1

@ShaunWilson: quale aspetto è falso? Si potrebbe definire un'interfaccia covariante 'IEventArgs', ma le sole classi che possono essere generiche per quanto riguarda i parametri di tipo generico sono delegati che non saranno alimentati a' Delegate.Combine'. I delegati che verranno usati con 'Delegate.Combine' non dovrebbero essere covarianti, dato che uno può essere memorizzato ad es. un 'azione 'in un campo di tipo' Azione ', ma un tentativo successivo di' Combina' che con un'istanza di 'Azione ' fallirà. – supercat

26

Devo dire che non capisco tutti i "puristi" qui. cioè se hai già definito una classe di borsa - che ha tutti i dettagli, proprietà ecc. - perché l'hack crea una classe extra non necessaria solo per essere in grado di seguire il meccanismo di evento/args, lo stile della firma? la cosa è - non tutto ciò che è in .NET - o "manca" per quella materia - è "buono" - MS si è "correttivo" da anni ... Direi di andare e crearne uno - come L'ho fatto - perché ne avevo bisogno proprio così - e mi ha risparmiato molto tempo,

+2

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

+8

non significava etichettare nessuno :) punto è nel 'generico' nell'evento - se hai solo bisogno di una dozzina di eventi diversi, ok. Ma se non conosci la natura del T in anticipo - che è noto solo al runtime - beh, hai bisogno di un evento generico. Quindi, se si dispone di un'app che tratta buona parte di generici, di un numero arbitrario di tipi, sconosciuti, allora sono necessari anche eventi generici. o, per esempio, non esiste una soluzione pulita per ogni problema, la regola empirica è solo una regola empirica - ed è quello che intendevo per puristi, ogni soluzione è diversa, devi pesare le cose, i pro ei contro – NSGaga

7

Esiste. Almeno, lo fa ora.

È possibile trovare DataEventArgs<TData> in alcuni assembly/namespace Microsoft diversi, 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.

+0

Sono stato cercando di trovare raccomandazioni e considerazioni su quando e perché utilizzare una classe EventArgs così generica. Vedi anche: http://stackoverflow.com/questions/15766219/ok-to-use-dataeventargstdata-instead-of-customized-event-data-class –

+0

Ecco alcuni aspetti da tenere in considerazione quando si decide di utilizzare un evento generico: http://stackoverflow.com/questions/129453/net-eventhandlers-generic-or-no/129613#129613 –

6

Se si sceglie di non utilizzare Prism, ma si desidera comunque provare un approccio generico EventArgs.

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 ObjAdded evento

public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded; 

// Utilizza il seguente codice di esempio per aumentare ObjAdded evento

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 GENERICHE INTEGRATE. Se segui il pattern Microsoft EventHandler, implementa il tuo EventArgs derivato come suggerito: public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.

TUTTAVIA - se il vostro stile di guida squadra accetta una semplificazione - il progetto può utilizzare un eventi leggero, in questo modo:

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 un progetti PoC utilizzare quest'ultimo approccio . In applicatons professionali, tuttavia, essere a conoscenza di FX poliziotto giustificazione # CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx