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