Pregunta

Hay una forma de comprobar si un objeto es un diccionario?

En un método que yo estoy tratando de obtener un valor de un elemento seleccionado en un cuadro de lista.En algunas circunstancias, el cuadro de lista puede ser obligado a un diccionario, pero esto no es conocido 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;
}

Es allí una manera de hacer esto de forma dinámica en tiempo de ejecución mediante la reflexión?Sé que es posible el uso de la reflexión con los tipos genéricos y determinar los parámetros de clave/valor, pero no estoy seguro de si hay una manera de hacer el resto después de esos valores se recuperan.

¿Fue útil?

Solución

Debe ser algo como lo siguiente.Escribí esto en el cuadro de respuesta por lo que la sintaxis puede no ser exactamente correcto, pero yo la he hecho Wiki editable para que cualquiera pueda arreglar.

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

Otros consejos

Compruebe si se implementa IDictionary.

Vea la definición de Sistema.Las colecciones.IDictionary a ver lo que te ofrece.

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

EDITAR: Alternativa cuando me di cuenta de KeyValuePair que no se puede lanzar 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 pesado, ListBox hace por usted.También si tienen generalmente los diccionarios como fuentes de datos que usted puede ser capaz de evitar el restablecimiento de ValueMember todo el tiempo.

Sé que esta pregunta se hizo hace muchos años, pero todavía es visible públicamente.

Existen pocos ejemplos que aquí se propone en este tema y en este:
Determinar si el tipo es un diccionario [duplicar]

pero hay algunos 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 larga:
Creo que esta es la razón por la que las personas cometen 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 tienen estos tipos:

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

y estas instancias:

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

así que si vamos a utilizar .IsAssignableFrom() método:

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

no llegaremos a ninguna instancia

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

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

usted puede comprobar para ver si se implementa IDictionary.Usted sólo tendrá que enumerar a través de la DictionaryEntry clase.

Usted podría ser un poco más genérico y preguntar si se implementa IDictionary.A continuación, el KeyValue colección se contina llanura Objects.

Yo creo que una advertencia de que está en su lugar.

Cuando tienes que probar si un objeto 'es un' algo esto o aquello, estás reimplementing (parte de) el tipo de sistema.El primer 'es una' a menudo es rápidamente seguido por una segunda, y pronto su código está lleno de comprobaciones de tipo, la cual debe ser muy bien manejado por el tipo de sistema - al menos en un diseño orientado a objetos.

Por supuesto, yo no sé nada de el contexto de la pregunta.Sé 2000 línea de archivos en nuestra base de código que se encarga de 50 objetos diferentes a las conversiones de cadenas...:(

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

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top