2012-04-18 17 views
6

È possibile trasmettere un valore Dictionary<string, Anything> a un tipo generico intermedio coerente? Quindi sarei in grado di trasmettere <string, string>, <string, bool>, <string, int>, <string, anything> tutti allo stesso tipo di dizionario?Dizionario cast di C# <string, AnyType> al dizionario <string, Object> (Coinvolgimento del riflesso)

Sto lavorando su un progetto che utilizza la riflessione pesante e ho bisogno di essere in grado di elaborare tipi dizionario come ad esempio:

FieldInfo field = this.GetType().GetField(fieldName); 
Dictionary<string, Object> dict = (Dictionary<string, Object>)field.GetValue(this); 

Il codice di cui sopra è quello che ho attualmente e il programma non riesce sempre a cast da field.GetValue al generico Dictionary<string, Object>.

C'è un modo per farlo? O dovrei solo capire un modo diverso per elaborare questi dizionari?

Qualsiasi aiuto sarebbe molto apprezzato.

risposta

8

seguito AakashM's answer, il Cast non sembra giocare a palla. È possibile ottenere intorno ad esso utilizzando un po 'di metodo di supporto però:

IDictionary dictionary = (IDictionary)field.GetValue(this); 
Dictionary<string, object> newDictionary = CastDict(dictionary) 
              .ToDictionary(entry => (string)entry.Key, 
                 entry => entry.Value); 

private IEnumerable<DictionaryEntry> CastDict(IDictionary dictionary) 
{ 
    foreach (DictionaryEntry entry in dictionary) 
    { 
     yield return entry; 
    } 
} 

La tipizzazione anatra in foreach è utile in questo caso.

+0

Questo ha funzionato come un fascino, grazie ad entrambi AakashM e Gibsnag. Questo mi stava dando problemi per un po '. –

+2

Non è necessario un metodo CastDict speciale, è sufficiente utilizzare il normale operatore di cast () LINQ. –

5

Ti sta aiutando?

Dictionary<a, b> output = 
    input.ToDictionary(item => item.Key, item => (SomeType)item.Value); 
+0

Non posso effettivamente chiamare il metodo ToDictionary poiché utilizzo la riflessione. Potrei essere in grado di utilizzare più riflessioni per arrivare al metodo ToDictionary, ma in tal caso non sarei sicuro su come passare quei tipi di parametri. –

8

Anche se si poteva trovare un modo per esprimere questo, sarebbe la cosa sbagliata da fare - non è vero che un Dictionary<string, bool>è un Dictionary<string, object>, quindi abbiamo sicuramente non voglio gettati . Considera che se noi avessimo il cast, potremmo provare a mettere un string come valore, che ovviamente non si adatta!

Cosa possiamo fare, tuttavia, è gettato alla non generica IDictionary (che tutti Dictionary<,> s implementano), quindi utilizzare che per costruire un nuovoDictionary<string, object> con gli stessi valori:

FieldInfo field = this.GetType().GetField(fieldName); 
IDictionary dictionary = (IDictionary)field.GetValue(this); 
Dictionary<string, object> newDictionary = 
    dictionary 
    .Cast<dynamic>() 
    .ToDictionary(entry => (string)entry.Key, 
        entry => entry.Value); 

(notare che non è possibile utilizzare .Cast<DictionaryEntry> qui per the reasons discussed here. Se siete pre-C# 4, e quindi non hanno dynamic, dovrete fare l'enumerazione manualmente, come Gibsnag's answer does)

+0

Ricevo ancora un errore "Il cast specificato non è valido" con quel codice. Qualche idea? –

+0

Qual è il tipo effettivo dell'oggetto che 'field.GetValue()' restituisce? – AakashM

+0

Beh, so per certo che sta cercando di ottenere un 'Dictionary ' ma è solo perché è il mio primo test case. Durante il runtime 'Console.WriteLine (field.GetValue (this) .GetType(). Name);' stampa out "Dictionary'2". Modifica: ho appena eseguito 'Console.WriteLine (field.GetValue (this));' e ho ottenuto 'System.Collections.Generic.Dictionary'2 [System.String, System.String]' –

0

sì, è possibile lanciare il FieldInfo-Dictionary come di seguito

Questo è un esempio, ho usato nel mio codice

Dictionary<string, string> 
       GetTheDict = FilesAndPaths.GetType() 
          .GetFields() 
          .Where(f => f.Name.Equals(pLoadFile)) 
          .Select(f => (Dictionary<string, string>)f.GetValue(FilesAndPaths)) 
          .Single(); 
0

Considerare se la fusione da e per object è davvero necessario. Ho iniziato su questa strada e mi sono imbattuto in questo articolo, prima di rendermi conto che avrei potuto ottenere ciò di cui avevo bisogno attraverso i generici piuttosto che la conversione. Per esempio;

class DictionaryUtils<T> 
{ 
    public static T ValueOrDefault(IDictionary<string, T> dictionary, string key) 
    { 
     return dictionary.ContainsKey(key) ? dictionary[key] : default(T); 
    } 
} 

Questo bit di codice è molto più pulito e sarà più veloce del codice di conversione equivalente mostrato in altre risposte.

Problemi correlati