2009-10-24 10 views
35

È possibile in C# creare System.Collections.Generic.Dictionary<TKey, TValue> dove TKey è una classe incondizionata e TValue - una classe anonima con un numero di proprietà, ad esempio - nome colonna del database e nome localizzato.Un dizionario in cui il valore è un tipo anonimo in C#

Qualcosa di simile a questo:

new { ID = 1, Name = new { Column = "Dollar", Localized = "Доллар" } } 
+0

Molto simile (con LINQ): [Un elenco generico di classe anonima] (http://stackoverflow.com/questions/612689/a-generic-list- di-anonimo-classe) – nawfal

+0

.Seleziona (...). AsEnumerable(). ToDictionary (k => k.id, v => v come oggetto) ha funzionato per me. La mia variabile era Dictionary Ravi

+0

@Ravishankar: Non è necessario 'AsEnumerable()' qui, molto probabilmente. Non aggiunge nulla sopra a 'Select()'. – abatishchev

risposta

38

Non è possibile dichiarare un tale tipo dizionario direttamente (ci sono kludges ma questi sono per l'intrattenimento e novità scopi solo), ma se i dati sono provenienti da un IEnumerable o fonte IQueryable, è possibile ottenere uno che utilizza l'operatore LINQ ToDictionary e proiettando la chiave richiesta e il valore (in forma anonima digitato) dagli elementi della sequenza:

var intToAnon = sourceSequence.ToDictionary(
    e => e.Id, 
    e => new { e.Column, e.Localized }); 
16

Come itowlsonsaid, non si può dichiarare come una bestia, ma è possibile infatti creare uno:

static IDictionary<TKey, TValue> NewDictionary<TKey, TValue>(TKey key, TValue value) 
{ 
    return new Dictionary<TKey, TValue>(); 
} 

static void Main(string[] args) 
{ 
    var dict = NewDictionary(new {ID = 1}, new { Column = "Dollar", Localized = "Доллар" }); 
} 

non è chiaro il motivo per cui ci si vuole realmente uso codice come questo.

+10

Perché? Posso pensare a una serie di ragioni. Eccone uno Si consideri ad esempio un dizionario utilizzato per memoizzare una funzione n-ario, ad esempio una funzione di quattro argomenti int. Nella prossima versione del CLR, ovviamente, useresti solo una tupla da 4, ma in C# 3, potresti creare un dizionario di tipo anonimo {int, int, int, int}, fatto, senza bisogno di definire il tuo tipo di tupla. –

+9

Ora ho un'altra voce per la sezione "pennelli con fama" della mia homepage personale! :-) –

3

Si può fare un riflesso

public static class ObjectExtensions 
{ 
    /// <summary> 
    /// Turn anonymous object to dictionary 
    /// </summary> 
    /// <param name="data"></param> 
    /// <returns></returns> 
    public static IDictionary<string, object> ToDictionary(this object data) 
    { 
     var attr = BindingFlags.Public | BindingFlags.Instance; 
     var dict = new Dictionary<string, object>(); 
     foreach (var property in data.GetType().GetProperties(attr)) 
     { 
      if (property.CanRead) 
      { 
       dict.Add(property.Name, property.GetValue(data, null)); 
      } 
     } 
     return dict; 
    } 
} 
+0

Buona idea. Inoltre puoi renderlo generico: 'public static IDictionary ToDictionary (questo oggetto dati) {}' – abatishchev

3

Penso ASP.NET MVC non ha uscita al momento questa domanda è stata fatta. Converte internamente oggetti anonimi in dizionari.

Basta dare un'occhiata allo HtmlHelper class, ad esempio. Il metodo che traduce gli oggetti nei dizionari è lo AnonymousObjectToHtmlAttributes. È specifico per MVC e restituisce un RouteValueDictionary, tuttavia.

Se volete qualcosa di più generico, provate questo:

public static IDictionary<string,object> AnonymousObjectToDictionary(object obj) 
{ 
    return TypeDescriptor.GetProperties(obj) 
     .OfType<PropertyDescriptor>() 
     .ToDictionary(
      prop => prop.Name, 
      prop => prop.GetValue(obj) 
     ); 
} 

Uno intersting advatages di questa implementazione è che restituisce un dizionario vuoto per null oggetti.

Ed ecco una versione generica:

public static IDictionary<string,T> AnonymousObjectToDictionary<T>(
    object obj, Func<object,T> valueSelect 
) 
{ 
    return TypeDescriptor.GetProperties(obj) 
     .OfType<PropertyDescriptor>() 
     .ToDictionary<PropertyDescriptor,string,T>(
      prop => prop.Name, 
      prop => valueSelect(prop.GetValue(obj)) 
     ); 
} 
+0

Grazie per avermelo detto! Lo svantaggio di tale metodo che posso nominare sta usando la riflessione. – abatishchev

+0

@abatishchev Penso che sia impossibile risolvere il problema senza riflettere. Non sono sicuro, ma leggere le proprietà con TypeDescriptor potrebbe essere più efficiente rispetto a un normale .GetType(). GetProperties(). A proposito, ho usato ILSpy su HtmlHelper e fa quasi esattamente la stessa cosa. – jpbochi