Comprobando si un objeto es un diccionario en C#


14

¿Hay alguna forma de comprobar si un objeto es un diccionario?

En un método estoy tratando de obtener un valor de un elemento seleccionado en un cuadro de lista. En algunas circunstancias, el cuadro de lista puede estar vinculado a un diccionario, pero esto no se conoce en tiempo de compilación.

me gustaría hacer algo similar a esto:

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

¿Hay una manera de hacer esto de forma dinámica en tiempo de ejecución utilizando la reflexión? Sé que es posible usar la reflexión con tipos genéricos y determinar los parámetros de clave/valor, pero no estoy seguro de si hay alguna manera de hacer el resto después de recuperar esos valores.

10

Debe ser algo como lo siguiente. Escribí esto en el cuadro de respuestas para que la sintaxis no sea exactamente la correcta, pero he hecho que Wiki sea editable para que cualquiera pueda arreglarlo.

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

probablemente funcionaría mejor usando el valor encerrado que usando la reflexión. 23 sep. 082008-09-23 19:33:30

  0

No estoy seguro de lo que quieres decir? No puede simplemente colocar un KeyValuePair <TKey,TValue> para extraer el valor del mismo. 23 sep. 082008-09-23 19:38:02

  0

Su solución funcionó. Cambié la declaración if para continuar y simplemente probar "is IDictionary" (el tipo de parte de la tuya no funcionó por algún motivo). También cambié "typeof (KeyValuePair <,>)" a "listBox.SelectedItem" 23 sep. 082008-09-23 20:04:40

  0

@Guvante En realidad, puede omitir los parámetros de tipo cuando se usa 'typeof' con un tipo genérico. Vea aquí: http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx 23 oct. 132013-10-23 13:28:00

  0

@TimGoodman: Es extraño, probé esa sintaxis y obtuve un error de compilación, eliminando. 23 oct. 132013-10-23 23:55:52


13

Comprueba si implementa IDictionary.

Consulte la definición de System.Collections.IDictionary para ver lo que le ofrece.

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

EDIT: Alternativa cuando me di cuenta de KeyValuePair no son moldeables a DictionaryEntry

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

Esta solución utiliza la reflexión, pero en este caso usted no tiene que hacer el trabajo sucio, ListBox lo hace por ti. Además, si generalmente tiene diccionarios como fuentes de datos, puede evitar reiniciar ValueMember todo el tiempo.

+3

Um, sabes IDictionary <TKey,TValue> en realidad no implementar la interfaz IDictionary ? Entonces esto no funcionará para diccionarios genéricos. Mira http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx 23 sep. 082008-09-23 19:32:36

  0

Además, incluso si fue un Dictionary <TKey,TValue> que implementa IDictionary, entonces implementa IEnumerable <KeyValuePair <TKey,TValue>> así que esperaría que caso de DictionaryEntry para fallar. 23 sep. 082008-09-23 19:39:05

  0

Por supuesto, quise decir "enviar a DictionaryEntry" arriba. 23 sep. 082008-09-23 19:44:31

  0

La conversión a DictionaryEntry falla. Todavía no he resuelto la solución todavía. 23 sep. 082008-09-23 19:50:26

+1

Bien para corregir a Greg Beech, acabo de sacar Dictionary <>, y de hecho implementa IDictionary, incluso si IDictionary <> no lo hace. Olvidé que aunque usar un método de indexación para obtener un DictionaryEntry funcionaría, no puedo convertir el SelectedItem en él. Se solucionará si encuentro una solución que no sea de reflexión. 24 sep. 082008-09-24 00:58:21


0

Puede ser un poco más genérico y preguntar en su lugar si implementa IDictionary. Luego, la colección de KeyValue contena llana Objects.

+1

Tenga cuidado con su terminología, refiriéndose a las versiones no genéricas como genérico es probablemente confuso para algunas personas (sé que siempre tengo que corregirme: P) 23 sep. 082008-09-23 19:26:37


1

puede verificar si implementa IDictionary. Simplemente tendrá que enumerar el uso de la clase DictionaryEntry.


0

I believe a warning is at place.

Cuando está probando si un objeto "es" algo así o lo otro, está reimplementando (parte de) el sistema de tipos. El primero 'es un' a menudo es seguido rápidamente por otro, y pronto su código está lleno de verificaciones de tipo, que el sistema de tipos debería manejar muy bien, al menos en un diseño orientado a objetos.

Por supuesto, no sé nada del contexto de la pregunta. Conozco a un archivo de línea 2000 en nuestra propia base de código que maneja 50 objeto diferente a la conversión de series ... :(


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

} 

3

Sé que esta pregunta se le preguntó hace muchos años, pero todavía es visible para el público.

había pocos ejemplos que aquí se proponen en este tema y en éste:
Determine if type is dictionary [duplicate]

pero hay pocos desajustes, así que quiero compartir mi solución

Respuesta corta:

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()))) 

Respuesta más larga:
Creo que esta es la razón por la cual la gente comete errores:

//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 

así que vamos a decir que tenemos estos tipos:

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

y estos casos:

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

por lo que si vamos a utilizar Método .IsAssignableFrom():

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

no vamos a obtener cualquier instancia

así que mejor manera es conseguir todas las interfaces y comprobar si alguno de ellos es la interfaz diccionario:

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