Question

Existe-t-il un moyen de tester si un objet est un dictionnaire?

Dans une méthode, j'essaie d'obtenir une valeur d'un élément sélectionné dans une zone de liste. Dans certaines circonstances, la liste peut être liée à un dictionnaire, mais cela n’est pas connu au moment de la compilation.

J'aimerais faire quelque chose de similaire à ceci:

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

Existe-t-il un moyen de le faire de manière dynamique lors de l'exécution à l'aide de la réflexion? Je sais qu'il est possible d'utiliser la réflexion avec des types génériques et de déterminer les paramètres clé / valeur, mais je ne suis pas sûr qu'il soit possible de faire le reste après avoir récupéré ces valeurs.

Était-ce utile?

La solution

Cela devrait ressembler à ce qui suit. J'ai écrit ceci dans la boîte de réponse, de sorte que la syntaxe n'est peut-être pas exacte, mais je l'ai rendu modifiable sur Wiki afin que tout le monde puisse le réparer.

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

Autres conseils

Vérifiez si elle implémente IDictionary.

Voir la définition de System.Collections.IDictionary pour voir ce que cela vous donne.

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

MODIFIER: Alternative quand j'ai réalisé que KeyValuePair ne peut pas être lancé dans DictionaryEntry

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

Cette solution utilise la réflexion, mais dans ce cas, vous n'avez pas à faire le gros travail, ListBox le fait pour vous. De même, si vous utilisez généralement des dictionnaires comme source de données, vous pouvez éventuellement éviter de réinitialiser à nouveau ValueMember.

Je sais que cette question a été posée il y a de nombreuses années, mais elle est toujours visible publiquement.

Peu d'exemples ont été proposés ici dans ce sujet et dans celui-ci:
Déterminer si le type est dictionnaire [en double]

mais il y a peu de différences, je veux donc partager ma solution

Réponse courte:

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

Réponse plus longue:
Je crois que c’est la raison pour laquelle les gens font des erreurs:

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

alors disons que nous avons ces types:

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

et ces instances:

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

donc si nous allons utiliser la méthode .IsAssignableFrom ():

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

nous n'obtiendrons aucune instance

Le meilleur moyen est donc d’obtenir toutes les interfaces et de vérifier si l’une d’elles est une interface de dictionnaire:

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

vous pouvez vérifier s'il implémente IDictionary . Vous devrez simplement énumérer la DictionaryEntry classe.

Vous pourriez être un peu plus générique et demander à la place si elle implémente IDictionary . Ensuite, la collection KeyValue se poursuivra en Objets .

Je crois qu'un avertissement est en place.

Lorsque vous testez si un objet 'est un' quelque chose ceci ou cela, vous réimplémentez (une partie du) système de types. Le premier 'est un' est souvent suivi rapidement par un second, et bientôt votre code regorge de vérifications de type, qui devraient être très bien gérées par le système de types - du moins dans une conception orientée objet.

Bien sûr, je ne connais rien du contexte de la question. Je connais un fichier de 2000 lignes dans notre propre base de code, qui gère 50 objets différents en conversions de chaînes ...: (

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

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top