Giocando con LINQ avrete senz'altro usato gli anonymous type: quei tipi creati al volo per contenere varie informazioni. Poniamo questo semplice esempio:
var v = new {Language = "IT", Age=30};Prima di tutto, v è visibile solo all'interno dello stack in cui l'abbiamo dichiarato. Quindi all'interno di una funzione o metodo, ma mai a livello di classe. Possiamo anche ritornarlo come valore da una funzione, ma potremmo limitarci a ritornare un tipo object generico e non potremmo fare riferimento al nome del tipo, facendo cast o quant'altro (se non via reflection, bleah bleah). Quindi ques'ultima opzione è fortemente sconsigliata.
Quando compiliamo, viene automaticamente generata una classe internal sealed dal nome f__AnonymousType[numero] sul namespace root. La classe eredita da Object definisce n proprietà e n campi per memorizzare i valori e dispone di un costruttore che accetta come parametri i valori da impostare sulle proprietà. Non c'è modo di cambiarne visibilità ai tipi o ai membri, ne di rendere in sola lettura le proprietà. Questa classe ha la particolarità di essere generica, nel senso che i tipi string e int delle proprietà Language e Age del nostro esempio, sono generici. Questo per evitare di creare copie della medesima classe. Quindi se utiliziamo nel medesimo assembly un anonymous type simile:
var v = new {Language = 1, Age=3d};verrà utilizzata la medesima classe autogenerata, ma con generics argument diversi: int e double.
Tale classe inoltre sovrascrive ToString per mostrare facilmente il contenuto, Equals e GetHashCode così da rendere comparabile il tipo quando viene utilizzato, per esempio da LINQ To Objects:
[DebuggerHidden]
public override string ToString()
{
StringBuilder builder = new StringBuilder();
builder.Append("{ Language = ");
builder.Append(this.<Language>i__Field);
builder.Append(", Age = ");
builder.Append(this.<Age>i__Field);
builder.Append(" }");
return builder.ToString();
}
[DebuggerHidden]
public override int GetHashCode()
{
int num = 0x5b485bf4; // Numero casuale
num = (-1521134295 * num) + EqualityComparer<<Language>j__TPar>.Default.GetHashCode(this.<Language>i__Field);
return ((-1521134295 * num) + EqualityComparer<<Age>j__TPar>.Default.GetHashCode(this.<Age>i__Field));
}
[DebuggerHidden]
public override bool Equals(object value)
{
var type = value as <>f__AnonymousType0<<Language>j__TPar, <Age>j__TPar>;
return (((type != null) && EqualityComparer<<Language>j__TPar>.Default.Equals(this.<Language>i__Field, type.<Language>i__Field)) && EqualityComparer<<Age>j__TPar>.Default.Equals(this.<Age>i__Field, type.<Age>i__Field));
}Sono interessanti l'uso di DebuggerHidden per evitare di far vedere dal debugger tali metodi e l'uso di EqualityComparer.Default per ottenere l'hashcode o comparare i tipi primitivi utilizzati. EqualityComparer.Default restituisce un IEqualityComparer<T> (fondamentale in LINQ) a seconda che il tipo implementi IEquatable<T>, sia nullabile o come ultima spiaggia, sovrascriva Equals e GetHashCode. Per comparare le stringhe (utile sempre in LINQ) abbiamo a disposizione la classe StringComparer che permette diversi modi di comparazione delle stringhe: CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, InvariantCultureIgnoreCase, Ordinal, OrdinalIgnoreCase.
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- WPF e Siverlight: Dispatcher e finestre modali, il 7 aprile 2009 alle 11:43
- Styles Explorer: decompilatore BAML, il 4 aprile 2008 alle 23:57
- Un'occhiata a Silverlight 2.0, il 6 marzo 2008 alle 23:13
- DirectShow e WPF: soluzione finale, il 28 gennaio 2008 alle 17:20
- Sorgenti custom per MediaElement di WPF, il 23 gennaio 2008 alle 12:49
