di .NET e di altre amenità

Extension Methods, Generics ed eventi

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.

WebHost4Life updates...

Che io sia venuto via da WenHost4Life credo sia di pubblico dominio. Rimane l'amaro in bocca per l'aver perso quello che era un efficace provider... ma le mail che mi stanno giungendo in questi giorni rispetto l'hosting che è tuttora attivo fino a naturale scadenza dimostrano (se necessario) la bontà delle mia decisione:

"We wanted to let you know that we have not yet received your payment of 0.00 for your "codeblock" account."

Ok. Resta tutto da capire cosa abbia causato questo immane disastro, ma che si siano fumati il cervello ormai è assodato.