Ultimamente sto usando Ninject che usa i generics in un modo che mi ha fatto ripensare al mio codice, in particolare mi sono imbattuto in un pattern che può essere riassunto cosi:
Ogniqualvolta un metodo ritorna un object è molto probabile che possa tornare un generics
Perchè?
Se un metodo ritorna un oggetto è molto probabile che si tratti di un metodo di una classe di factory, visto che
object è il padre di tutti gli oggetti, fino all avvento dei generics risultava naturale, ritornare o un interfaccia nota, o un
object generico.
Per esempio mi è capitato di usare questa metodologia quando ho creato uioc, un container ioc per cf2.0 ( http://codeplex.com/uIoC ) , che piu che un container ioc è una superfactory che richiama gli oggetti tramite stringa anzichè nome.
Comunque indipendentemente da questo, ritornare un object comporta il quasi sicuramente dovere fare un cast dove si richiama il metodo, esempio:
public class Pippo{
public object Get(string id){
return this.container[id];
}
}
....
Pippo p = new Pippo();
p.initialize();
IList lista = (IList)p.get("Lista di sviluppatori javascript");
se volessimo aggiungere uno sviluppatore dovremo fare o un
lista.add("Andrea Giammarchi");
oppure il scomodissimo
((Ilist)p.get("Lista di sviluppatori javascript")).add("Andrea Giammarchi");
se invece cambiassimo il metodo in
public T Get<T>(string id){
return this.container[id];
}
potremo scrivere
p.get<IList>("Lista di sviluppatori javascript").add("Andrea Giammarchi");
non abbiamo quadagnato molto in termini di codice scritto, ma abbiamo 2 vantaggi,
il primo è che l intellisense ci fornisce direttamente i metodi una volta chiusa la parentesi, senza dover esplicitare il cast
il secondo abbiamo eliminato il
boxing/unboxing Cast dell
IList che ci permette di non avere cast non validi a runtime
e nel contempo dovrebbe ottimizzare un po la velocità di esecuzione ( a scapito di un maggiore grandezza dell'eseguibile )
...e se dovessimo ritornare null?
potrebbe essere in metodi che ritornano un object che in caso di errore in creazione e affini si voglia tornare
null..
usando un generics ovviamente non è possibile tornare
null, ci viene in soccorso la keyword
default
esempio:
if(hoAvutoUnProblema){
// return null
return default(T);
}
che ritorna un valore di default.
Potremo applicare questa metodologia anche quando, per esempio, si deve passare un oggetto
Type come parametro ad un metodo, che ci costringe a scrivere
typeof(NostraClasse)
esempio anzichè:
public void register(string id, Type type){
this.container.add(id, type);
}
..
p.register("lista di programmatori",typeof(List<string>));
avremo:
public void register<T>(string id){
this.container.add(id,typeof(T));
}
..
p.register<List<string>>("lista di programmatori");
questo ci permette di scrivere qualche carattere in meno.