eventi<> vs evento EventHandler<>

C’è di diverso tra la dichiarazione event Action<> e event EventHandler<>.

Ammesso che non importa ciò che l’oggetto effettivamente sollevato un evento.

per esempio:

public event Action<bool, int, Blah> DiagnosticsEvent;

vs

public event EventHandler<DiagnosticsArgs> DiagnosticsEvent;

class DiagnosticsArgs : EventArgs
{
    public DiagnosticsArgs(bool b, int i, Blah bl)
    {...}
    ...
}

utilizzo sarebbe quasi la stessa in entrambi i casi:

obj.DiagnosticsEvent += HandleDiagnosticsEvent;

Ci sono diverse cose che non mi piace su event EventHandler<> modello:

  • Extra dichiarazione di tipo derivato da
    EventArgs
  • Di passaggio obbligatorio di origine dell’oggetto –
    spesso non si

Altro codice indica il codice più a mantenere, senza alcun vantaggio.

Come risultato, preferisco event Action<>

Tuttavia, solo se ci sono troppi argomenti di tipo in Azione<>, quindi un extra di classe sarebbe necessario.

  • plusOne (ho appena battuto il sistema) per “a nessuno importa”
  • In realtà ho bisogno di sapere il mittente! Dire qualcosa di happenes e volete sapere chi è stato. Che erano avete bisogno di oggetti ‘fonte’ (aka mittente).



6 Replies
  1. 66

    La principale differenza è che se si utilizza Action<> di un evento non seguire il modello di progettazione di qualsiasi altro evento nel sistema, che io considero uno svantaggio.

    Uno a testa con la dominante modello di progettazione (a parte il potere di uguaglianza) è che è possibile estendere la EventArgs con la nuova proprietà, senza alterare la firma dell’evento. Questo sarebbe possibile se si è utilizzato Action<SomeClassWithProperties>, ma non vedo il punto, non utilizzando l’approccio normale in questo caso.

    • Utilizzando Action<> causare perdite di memoria? Uno svantaggio con il EventHandler design pattern è di perdite di memoria. Inoltre deve essere sottolineato che non ci può essere più di Gestori di Eventi, ma una sola Azione
    • Gli eventi sono, in sostanza, i delegati, in modo che la stessa perdita di memoria con possibilità di esistere con Action<T>. Inoltre, un Action<T> può fare riferimento a diversi metodi. Qui è un gist che dimostra che: gist.github.com/fmork/4a4ddf687fa8398d19ddb2df96f0b434
  2. 84

    Basato su alcune delle risposte precedenti, ho intenzione di rompere la mia risposta in tre aree.

    Prima, le limitazioni fisiche di utilizzare Action<T1, T2, T2... > vs utilizzando una classe derivata di EventArgs. Ci sono tre: in Primo luogo, se si modifica il numero o i tipi di parametri, ogni metodo che sottoscrive dovrà essere modificato per soddisfare il nuovo modello. Se questo è un pubblico di fronte a un evento che 3rd party assemblee e non c’è alcuna possibilità che l’evento args cambiamento, questo sarebbe un motivo per utilizzare una classe derivata da event args per la consistenza del bene (ricordate, si PUÒ ancora usare un Action<MyCustomClass>) in Secondo luogo, utilizzando Action<T1, T2, T2... > ti impedisce il passaggio di RITORNO di feedback al metodo chiamante a meno che non si dispone di un qualche tipo di oggetto (con un Gestiti di proprietà, per esempio) che viene trasmesso con l’Azione. Terzo, non si ottiene parametri denominati, quindi se si sta passando da 3 bool‘un int, due string‘s, e un DateTime, non avete idea di quale sia il significato di quei valori che sono. Come nota a margine, è ancora possibile avere un “Fuoco di questo evento in modo sicuro metodo pur usando Action<T1, T2, T2... >“.

    In secondo luogo, la coerenza implicazioni. Se si dispone di un grande sistema che si sta già lavorando, è quasi sempre meglio seguire il modo in cui il resto del sistema è progettato a meno che non si dispone di una buona ragione per non farlo. Se si hanno pubblicamente di fronte a eventi che devono essere mantenute, la possibilità di sostituire le classi derivate possono essere importanti. Da tenere a mente.

    In terzo luogo, reale, vita pratica, personalmente trovo che tendono a creare un sacco di uno di eventi per cose come la struttura delle modifiche che ho bisogno di interagire con (in Particolare quando si fa MVVM con visualizzazione di modelli che interagire con gli altri) o in cui l’evento ha un solo parametro. La maggior parte del tempo questi eventi, sotto forma di public event Action<[classtype], bool> [PropertyName]Changed; o public event Action SomethingHappened;. In questi casi, ci sono due vantaggi. Primo, ho un tipo per il rilascio di classe. Se MyClass dichiara ed è l’unica classe di generazione dell’evento, ho una esplicita istanza di MyClass lavorare con un gestore di eventi. In secondo luogo, per eventi semplici come la proprietà a cambiare gli eventi, il significato dei parametri è evidente e dichiarato nel nome del gestore di eventi e non devo creare una miriade di classi per questi tipi di eventi.

    • Mi permetta di mettere il link al tuo post con più dettagliata e strutturata risposta paulrohde.com/events-eventhandler-or-action
    • Impressionante post di blog. Sicuramente vale la pena di leggere, se stai leggendo questo thread!
    • +1,leggere il tuo blog così, davvero utile!
    • Mappa e ben pensato di risposta che spiega le motivazioni per la conclusione
  3. 15

    La maggior parte, direi di seguire il modello. Ho hanno deviato da esso, ma molto raramente, e per motivi specifici. Nel caso In questione, il problema più grosso che mi piacerebbe avere è che probabilmente sarei ancora utilizzare un Action<SomeObjectType>, che mi permette di aggiungere proprietà in seguito, e per l’uso occasionale a 2 vie proprietà (si pensi Handled, o altri feedback-eventi in cui il sottoscrittore deve per set una proprietà dell’oggetto evento). E una volta che hai iniziato a scendere quella linea, si potrebbe anche utilizzare EventHandler<T> per alcuni T.

  4. 14

    Il vantaggio di un wordier approccio nasce quando il codice è all’interno di una linea di 300.000 progetto.

    Utilizzando l’azione, come voi, non c’è modo di dirmi cosa bool, int, e Bla sono. Se l’azione viene passato un oggetto che ha definito i parametri poi su ok.

    Utilizzando un EventHandler che voleva un EventArgs e se vuoi completare il tuo DiagnosticsArgs esempio con getter per le proprietà che hanno commentato il loro scopo è quindi l’applicazione sarebbe più comprensibile. Inoltre, si prega di commento, o completamente nome gli argomenti in DiagnosticsArgs costruttore.

  5. 6

    Se si seguono gli standard modello a eventi, allora si può aggiungere un metodo di estensione per effettuare il controllo della generazione dell’evento più sicuro e facile. (cioè il codice seguente aggiunge un metodo di estensione denominato SafeFire() che fa il controllo null, oltre (ovviamente) copia l’evento in una variabile distinta per essere al sicuro dai soliti null gara-condizioni che possono influenzare gli eventi.)

    (Anche se sono in genere di due menti se si deve utilizzare metodi di estensione su oggetti nulli…)

    public static class EventFirer
    {
        public static void SafeFire<TEventArgs>(this EventHandler<TEventArgs> theEvent, object obj, TEventArgs theEventArgs)
            where TEventArgs : EventArgs
        {
            if (theEvent != null)
                theEvent(obj, theEventArgs);
        }
    }
    
    class MyEventArgs : EventArgs
    {
        //Blah, blah, blah...
    }
    
    class UseSafeEventFirer
    {
        event EventHandler<MyEventArgs> MyEvent;
    
        void DemoSafeFire()
        {
            MyEvent.SafeFire(this, new MyEventArgs());
        }
    
        static void Main(string[] args)
        {
            var x = new UseSafeEventFirer();
    
            Console.WriteLine("Null:");
            x.DemoSafeFire();
    
            Console.WriteLine();
    
            x.MyEvent += delegate { Console.WriteLine("Hello, World!"); };
            Console.WriteLine("Not null:");
            x.DemoSafeFire();
        }
    }
    • … non si può fare la stessa cosa con Azione<T>? SafeFire<T> questo<T> theEvent, T theEventArgs) dovrebbe funzionare… e non c’è bisogno di usare il “dove”
  6. 3

    Guardando Standard .NET caso di modelli troviamo

    Firma standard per una .NET delegato dell’evento è:

    void OnEventRaised(object sender, EventArgs args);

    […]

    L’elenco di argomento contiene due argomenti: il mittente, e argomenti dell’evento. Il tempo di compilazione tipo di mittente è di Sistema.Oggetto, anche se probabilmente conoscete un più derivati tipo che vorresti essere sempre corretta. Per convenzione, l’uso oggetto.

    Di seguito sulla stessa pagina troviamo un esempio di tipica definizione di evento che è qualcosa di simile a

    public event EventHandler<EventArgs> EventName;

    Avevamo definito

    class MyClass
    {
      public event Action<MyClass, EventArgs> EventName;
    }

    il gestore avrebbe potuto essere

    void OnEventRaised(MyClass sender, EventArgs args);

    dove sender è corretta (più derivati) tipo.

    • La domanda era se c’è qualche differenza…
    • Mi dispiace di non aver risposto che la differenza è nel gestore di firma, che potrebbe beneficiare di un più precisamente digitato sender.

Lascia un commento