Una delle caratteristiche degli extension methods che mi piace di più è la possibilità di chiamarli anche su variabili che siano "null", ovvero che non contengano alcun istanza. Tipicamente il "null" è uno di quei casi che dobbiamo sempre gestire e che ci costringe ad usare più condizioni di quelle che realmente servano. Poniamo ad esempio di dover invocare un evento all'interno di un controllo. Prima degli extension methods il codice che usavo era più o meno questo:

   1: EventHandler<EventArgs> handler = this.Clicked;
   2:  
   3: if (handler != null)
   4:     handler.Invoke(this, EventArgs.Empty);

In buona sostanza si verifica prima che qualcuno abbia "agganciato" l'EventHandler, nel qual caso la variabile non sarà "null", e poi si esegue il metodo Invoke che esegue il delegate. La prima riga, che può sembrare inutile, ha la importante funzione di prendere un riferimento all'evento allo scopo di evitare che una eventuale garbage collection ci "rubi" l'EventHandler sotto il naso causando una NullReferenceException nonostante la verifica di cui sopra.

Buona norma è mettere il codice in un metodo "OnClicked", anche se nella mia esperienza ho visto molti ripetere più volte il controllo in un unico blocco di codice (ma questo è un'altro problema...). Il codice, comunque sia, è ampiamente ripetitivo, soprattutto se il controllo espone decine di eventi, e può essere generalizzato usando un generic. Questo vale ovviamente se  non abbiamo l'esigenza di consentire l'override del metodo OnClicked. In questo caso non c'è alternativa. Se invece, come spesso accade, esporre l'override non è utile ecco un codice un po' più furbo

   1: protected void Raise<T>(EventHandler<T> handler, T e)
   2:     where T : EventArgs
   3: {
   4:     if (handler != null)
   5:         handler.Invoke(this, e);
   6: }
   7:  
   8: // --- chiamato così
   9:  
  10: this.Raise(this.Clicked, EventArgs.Empty);

Questo metodo fa uso dell'EventHandler generico e sostanzialmente ci toglie un bel po' di codice. Innanzitutto, dato che l'handler è passato come argomento diventa implicitamente assegnato ad una variabile (il parametro) e quindi siamo al sicuro dalla Garbage Collection, in secondo luogo con una sola riga facciamo tutto quello che ci serve. Si può però fare meglio, e qui entrano in gioco gli Extension Methods:

   1: public static class EventUtils
   2: {
   3:     public static void Raise<T>(this EventHandler<T> handler, object sender, T args)
   4:         where T : EventArgs
   5:     {
   6:         if (handler != null)
   7:             handler.Invoke(sender, args);
   8:     }
   9: }
  10:  
  11: // -- chiamato così
  12:  
  13: this.Clicked.Raise(this, EventArgs.Empty);

Estraendo il metodo dalla classe cui si riferisce il codice diventa molto più riutilizzabile. Grazie all'uso di un Extension Method poi tutto risulta nettamente più leggibile. Il mio consiglio è di creare una classe EventUtils ricca di metodi, che ci consentano di gestire più o meno tutti i casi possibili, con l'EventHandler generico ma anche con quello normale che spesso e volentieri è più che sufficiente per molti utilizzi.

tags: - categories:

Aggiungi Commento