Anonymous type di C# 3.0

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.

Nella stessa categoria

Commenti

Per inserire un commento, devi registrarti alla nostra community.

© 1998-2008 - Ricciolo.NET - Il blog di Cristian "Ricciolo" Civera

TagCloud
BLOG INFO
  • Post: 169
  • Commenti: 74
  • TrackBacks: 37
  • Feed blog e contenuti tecnici: RSS
  • Feed blog: RSS Atom OPML

MVP
CATEGORIE
I PIÙ LETTI DEL MESE
IN EVIDENZA