Chiamare un metodo di estensione su un riferimento "null" (cioè un evento senza abbonati) è male?

StackOverflow https://stackoverflow.com/questions/248072

  •  05-07-2019
  •  | 
  •  

Domanda

Male o non male?

public static void Raise(this EventHandler handler, object sender, EventArgs args)
{
   if (handler != null)
   {
      handler(sender, args);
   }
}

// Usage:
MyButtonClicked.Raise(this, EventArgs.Empty);

// This works too! Evil?
EventHandler handler = null;
handler.Raise(this, EVentArgs.Empty);

Si noti che a causa della natura dei metodi di estensione, MyButtonClicked.Raise non genererà una NullReferenceException se MyButtonClicked è null. (Ad esempio, non ci sono ascoltatori dell'evento MyButtonClicked).

Il male o no?

È stato utile?

Soluzione

Non male. Vorrei che gli eventi funzionassero in questo modo per impostazione predefinita. Qualcuno può spiegare perché un evento senza abbonati è nullo?

Altri suggerimenti

Puoi sempre dichiarare i tuoi eventi in questo modo (non che io lo consiglio):

public event EventHandler<EventArgs> OnClicked = delegate { };

In questo modo hanno qualcosa assegnato loro quando li chiami, quindi non generano un'eccezione puntatore null.

Probabilmente puoi sbarazzarti della parola chiave delegata in C # 3.0 ...

Non dimenticare di usare [MethodImpl (MethodImplOptions.NoInlining)] , altrimenti è possibile che non sia thread-safe.

(Leggilo da qualche parte molto tempo fa, ricordato, cercato su Google e trovato http: //blog.quantumbitdesigns. com / tag / events / )

Provenendo da uno sfondo Java, questo mi è sempre sembrato strano. Penso che nessuno che ascolti un evento sia perfettamente valido. Soprattutto quando gli ascoltatori vengono aggiunti e rimossi in modo dinamico.

Per me questo sembra uno dei gottcha di C # che causa bug quando le persone non sanno / dimenticano di controllare ogni volta null.

Nascondere questi dettagli di implementazione sembra un buon piano in quanto non aiuta la leggibilità per verificare la presenza di valori null ogni volta. Sono sicuro che gli MSFT diranno che c'è un miglioramento delle prestazioni nel non costruire l'evento se nessuno è in ascolto, ma immagino che sia ampiamente compensato dalle inutili eccezioni / riduzioni del puntatore nullo nella maggior parte del codice aziendale.

Aggiungerei anche questi due metodi alla classe:

    public static void Raise(this EventHandler handler, object sender)
    {
        Raise(handler, sender, EventArgs.Empty);
    }

    public static void Raise<TA>(this EventHandler<TA> handler, object sender, TA args)
        where TA : EventArgs
    {
        if (handler != null)
        {
            handler(sender, args);
        }
    }

Perché dovrebbe essere malvagio?

Il suo scopo è chiaro: genera l'evento MyButtonClicked.

Aggiunge un overhead di chiamata di funzione, ma in .NET sarà comunque ottimizzato o piuttosto veloce.

È leggermente banale, ma risolve la mia più grande lamentela con C #.

Nel complesso, penso che sia un'idea fantastica e probabilmente la ruberò.

Non direi che è malvagio, ma sono interessato a come il tuo metodo di estensione si adatta a

protected virtual OnSomeEvent(EventArgs e){ }

modello e come gestisce l'estensibilità tramite ereditarietà. Presume che tutte le sottoclassi gestiranno l'evento invece di sovrascrivere un metodo?

Anche se non lo descriverei come male , ha ancora un'implicazione negativa, in quanto aggiunge un sovraccarico non necessario:

Quando si chiama

myEvent.Raise (this, new EventArgs ());

l'oggetto EventArgs è inizializzato in tutte le situazioni, anche se nessuno si è iscritto a myEvent.

Quando si utilizza

if (myEvent!= null) {
   myEvent(this, new EventArgs());
}

EventArgs viene inizializzato solo se qualcuno si è abbonato a myEvent.

Generare un'eccezione quando non ci sono gestori non è davvero preferibile per la maggior parte. Se non ha un gestore, è meglio essere vuoti piuttosto che nulli.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top