Claudio Brotto

Due note sugli Extension Methods

Gli "Extension Methods" sono una caratteristica sintattica introdotta dai compilatori C# 3.0 e VB 9.0 (che NON è .NET 3.0, e qui scusatemi l'excursus ma siamo alle solite, si rischia sempre di fare confusione con questi numeri di versione "sovrapposti").

Sottolineo il termine "sintattica" perchè non hanno nulla a che vedere con il runtime, nè strutturalmente nè funzionalmente.

Molto semplicemente, invece, sono state aggiunte regole di risoluzione.

Mi spiego, prendendo ad esempio il codice qui sotto:

 

String[] codici = new String[] {"11", "12", "13"};

Object soloQualcheCodice = codici.Where(.....)

 

Quando incontra lo statement codici.Where(), il compilatore segue le consuete regole di lookup in modo da individuare il metodo corretto da invocare.

Regole che, per come siamo abituati a conoscerle, in questo caso falliscono !

Non esiste alcun metodo public instance Where in String[], nè in alcuna delle sue classi di base in gerarchia.

 

Gli extension methods sfruttano, fondamentalmente, nuove regole di lookup aggiunte al compilatore: il quale, falliti i tentativi “standard”, va a verificare che non esista un metodo “valido” in qualche altro posto.

L’altro posto è una qualche classe statica, avente un metodo statico “compatibile”, e in scope dal punto di chiamata (nel namespace corrente e su a salire in base alle direttive using).

 

“Compatibile” in questo contesto significa che, data l’invocazione (pseudo-codice):

 

T istanza = ...

Int32 i = istanza.Metodo()

 

se non esiste un metodo utilizzabile il compilatore cerca (in base alle regole accennate in precedenza) un metodo con firma:

 

static Int32 Metodo(this T istanza, )

 

E se lo trova emette la chiamata ad esso.

 

Da notare che comunque, in caso di overload, i metodi di istanza hanno la precedenza

 

Per esempio, dati:

 

class Esempio

{

  public void Scrivi (Object o) {}

}

 

e

 

public static class Estensione

{

  public static void Scrivi(this Esempio e, Int32 numero) {}

}

 

Una chiamata a:

 

Esempio e = new Esempio();

e.Scrivi(10);

 

viene risolta invocando la versione instance, per quanto meno “specializzata”.

 

E, piccola considerazione per rispondere ad una domanda che mi è stata posta in più di un’occasione: gli extension methods NON sono un modo per ereditare da classi sealed !

Sono concetti parecchio differenti.

A mio parere (si accettano ovviamente critiche e suggerimenti) farne un uso estensivo per, che so, definire mille nuove funzionalità della classe String non è la migliore delle cose.

Soprattutto dal punto di vista della leggibilità e della chiarezza del codice per chi, quel codice, non lo ha scritto.

Continuo a preferire una chiamata esplicita, tipo

 

StringHelpers.DecodeString(“ciao”)

 

Piuttosto che

 

“ciao”.Decode()

 

Ovvio che il secondo metodo è più conciso e diretto, ma forse è anche meno leggibile per il lettore “occasionale” del nostro codice.

Posted: nov 30 2006, 07.20 by devlizard | with no comments
Filed under: