Verificare se un oggetto è un dizionario in C#


14

C'è un modo per verificare se un oggetto è un dizionario?

In un metodo sto cercando di ottenere un valore da un elemento selezionato in una casella di riepilogo. In alcune circostanze, la casella di riepilogo potrebbe essere associata a un dizionario, ma questo non è noto al momento della compilazione.

mi piacerebbe fare qualcosa di simile a questo:

if (listBox.ItemsSource is Dictionary<??>) 
{ 
    KeyValuePair<??> pair = (KeyValuePair<??>)listBox.SelectedItem; 
    object value = pair.Value; 
} 

Esiste un modo per fare questo in modo dinamico in fase di esecuzione utilizzando la riflessione? So che è possibile utilizzare il reflection con tipi generici e determinare i parametri chiave/valore, ma non sono sicuro se c'è un modo per fare il resto dopo che questi valori sono stati recuperati.

10

Dovrebbe essere qualcosa come il seguente. Ho scritto questo nella casella di risposta, quindi la sintassi potrebbe non essere corretta, ma ho reso Wiki modificabile in modo che chiunque possa risolvere il problema.

if (listBox.ItemsSource.IsGenericType && 
    typeof(IDictionary<,>).IsAssignableFrom(listBox.ItemsSource.GetGenericTypeDefinition())) 
{ 
    var method = typeof(KeyValuePair<,>).GetProperty("Value").GetGetMethod(); 
    var item = method.Invoke(listBox.SelectedItem, null); 
} 
  0

probabilmente funzionerebbe meglio usando il valore in box rispetto all'utilizzo del reflection. 23 set. 082008-09-23 19:33:30

  0

Non sono sicuro di cosa intendi? Non puoi semplicemente inscatolare KeyValuePair <TKey,TValue> per estrarre il valore da esso. 23 set. 082008-09-23 19:38:02

  0

La tua soluzione ha funzionato. Ho cambiato la dichiarazione if per andare avanti e testare "è IDictionary" (il tipo di una parte del tuo non ha funzionato per qualche motivo). Ho anche modificato "typeof (KeyValuePair <,>)" in "listBox.SelectedItem" 23 set. 082008-09-23 20:04:40

  0

@Guvante In realtà, è possibile omettere i parametri del tipo quando si utilizza 'typeof' con un tipo generico. Vedi qui: http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx 23 ott. 132013-10-23 13:28:00

  0

@TimGoodman: È strano, ho provato la sintassi e ho ottenuto un errore di compilazione, rimuovendo. 23 ott. 132013-10-23 23:55:52


13

Verificare se implementa IDictionary.

Vedere la definizione di System.Collections.IDictionary per vedere cosa ti offre.

if (listBox.ItemsSource is IDictionary) 
{ 
    DictionaryEntry pair = (DictionaryEntry)listBox.SelectedItem; 
    object value = pair.Value; 
} 

EDIT: alternativa, quando mi sono reso conto di KeyValuePair non sono calcinabile per DictionaryEntry

if (listBox.DataSource is IDictionary) 
{ 
    listBox.ValueMember = "Value"; 
    object value = listBox.SelectedValue; 
    listBox.ValueMember = ""; //If you need it to generally be empty. 
} 

Questa soluzione utilizza la riflessione, ma in questo caso non c'è bisogno di fare il lavoro sporco, ListBox lo fa per te. Inoltre, se generalmente hai dizionari come fonti di dati, potresti essere in grado di evitare il reset di ValueMember tutto il tempo.

+3

Uhm, sai IDictionary <TKey,TValue> in realtà non implementa l'interfaccia IDictionary ? Quindi questo non funzionerà con i dizionari generici. Guarda http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx 23 set. 082008-09-23 19:32:36

  0

Inoltre, anche se fosse un dizionario <TKey,TValue> che implementa IDictionary, implementa IEnumerable <KeyValuePair <TKey,TValue>> quindi mi aspetto che il caso a DictionaryEntry fallire. 23 set. 082008-09-23 19:39:05

  0

Ovviamente intendevo "cast to DictionaryEntry" sopra. 23 set. 082008-09-23 19:44:31

  0

Trasmissione a DictionaryEntry non riesce. Ancora non ho ancora capito la soluzione. 23 set. 082008-09-23 19:50:26

+1

Bene per correggere Greg Beech, ho appena tirato su Dizionario <>, e in effetti implementa l'IDictionary, anche se IDictionary <> non lo fa. Hai dimenticato che, sebbene l'utilizzo di un metodo di indicizzazione per ottenere un DictionaryEntry potesse funzionare, non posso eseguire il cast di SelectedItem. Risolverà se trovo una soluzione non riflettente. 24 set. 082008-09-24 00:58:21


0

Potrebbe essere un po 'più generico e chiedere invece se implementa IDictionary. Quindi la collezione KeyValue verrà contina nuda Objects.

+1

Fai attenzione alla tua terminologia, fare riferimento alle versioni non generiche come generiche è probabilmente fonte di confusione per alcune persone (so che devo sempre correggermi: P) 23 set. 082008-09-23 19:26:37


1

è possibile verificare se implementa IDictionary. Dovrai semplicemente enumerare l'utilizzo della classe DictionaryEntry.


0

Credo che un avviso sia a posto.

Quando si verifica se un oggetto 'è un' qualcosa questo o quello, si sta reimplementando (parte) il sistema di tipi. Il primo 'è un' è spesso seguito rapidamente da un secondo, e presto il tuo codice è pieno di controlli di tipo, che dovrebbero essere gestiti molto bene dal sistema di tipi - almeno in un design orientato agli oggetti.

Naturalmente, non conosco il contesto della domanda. Io conosco un file linea 2000 nella nostra base di codice che gestisce 50 oggetto diverso alle conversioni String ... :(


0
if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType())) 
{ 

} 

3

So che questa domanda è stato chiesto molti anni fa, ma è ancora visibile al pubblico.

c'erano pochi esempi proposti qui in questo argomento e in questo uno:
Determine if type is dictionary [duplicate]

ma ci sono alcuni disallineamenti, quindi voglio condividere la mia soluzione

Risposta breve:

var dictionaryInterfaces = new[] 
{ 
    typeof(IDictionary<,>), 
    typeof(IDictionary), 
    typeof(IReadOnlyDictionary<,>), 
}; 

var dictionaries = collectionOfAnyTypeObjects 
    .Where(d => d.GetType().GetInterfaces() 
     .Any(t=> dictionaryInterfaces 
      .Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition()))) 

Risposta più lunga:
Credo che questo sia il motivo per cui le persone commettono errori:

//notice the difference between IDictionary (interface) and Dictionary (class) 
typeof(IDictionary<,>).IsAssignableFrom(typeof(IDictionary<,>)) // true 
typeof(IDictionary<int, int>).IsAssignableFrom(typeof(IDictionary<int, int>)); // true 

typeof(IDictionary<int, int>).IsAssignableFrom(typeof(Dictionary<int, int>)); // true 
typeof(IDictionary<,>).IsAssignableFrom(typeof(Dictionary<,>)); // false!! in contrast with above line this is little bit unintuitive 

quindi cerchiamo dire che abbiamo questi tipi:

public class CustomReadOnlyDictionary : IReadOnlyDictionary<string, MyClass> 
public class CustomGenericDictionary : IDictionary<string, MyClass> 
public class CustomDictionary : IDictionary 

e queste istanze:

var dictionaries = new object[] 
{ 
    new Dictionary<string, MyClass>(), 
    new ReadOnlyDictionary<string, MyClass>(new Dictionary<string, MyClass>()), 
    new CustomReadOnlyDictionary(), 
    new CustomDictionary(), 
    new CustomGenericDictionary() 
}; 

quindi se useremo Metodo .IsAssignableFrom():

var dictionaries2 = dictionaries.Where(d => 
    { 
     var type = d.GetType(); 
     return type.IsGenericType && typeof(IDictionary<,>).IsAssignableFrom(type.GetGenericTypeDefinition()); 
    }); // count == 0!! 

non otterremo alcun caso

così modo migliore è quello di ottenere tutte le interfacce e verificare se qualcuno di loro è l'interfaccia dizionario:

var dictionaryInterfaces = new[] 
{ 
    typeof(IDictionary<,>), 
    typeof(IDictionary), 
    typeof(IReadOnlyDictionary<,>), 
}; 

var dictionaries2 = dictionaries 
    .Where(d => d.GetType().GetInterfaces() 
     .Any(t=> dictionaryInterfaces 
      .Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition()))) // count == 5