Проверка, является ли объект словарём в C # - PullRequest
14 голосов
/ 23 сентября 2008

Есть ли способ проверить, является ли объект словарем?

В методе я пытаюсь получить значение из выбранного элемента в списке. В некоторых случаях список может быть связан со словарем, но это не известно во время компиляции.

Я хотел бы сделать что-то похожее на это:

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

Есть ли способ сделать это динамически во время выполнения, используя отражение? Я знаю, что можно использовать отражение с универсальными типами и определять параметры ключ / значение, но я не уверен, есть ли способ сделать остальное после получения этих значений.

Ответы [ 7 ]

13 голосов
/ 23 сентября 2008

Проверьте, реализует ли он IDictionary.

См. Определение System.Collections.IDictionary, чтобы увидеть, что это дает вам.

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

EDIT: Альтернатива, когда я понял, что KeyValuePair не могут быть преобразованы в DictionaryEntry

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

В этом решении используется рефлексия, но в этом случае вам не нужно выполнять грубую работу, ListBox сделает это за вас. Кроме того, если у вас обычно есть словари в качестве источников данных, вы можете избежать постоянного сброса ValueMember.

10 голосов
/ 23 сентября 2008

Это должно быть что-то вроде следующего. Я написал это в поле для ответов, так что синтаксис может быть не совсем правильным, но я сделал его вики редактируемым, так что любой может исправить.

if (listBox.ItemsSource.IsGenericType && 
    typeof(IDictionary<,>).IsAssignableFrom(listBox.ItemsSource.GetGenericTypeDefinition()))
{
    var method = typeof(KeyValuePair<,>).GetProperty("Value").GetGetMethod();
    var item = method.Invoke(listBox.SelectedItem, null);
}
3 голосов
/ 15 апреля 2015

Я знаю, что этот вопрос задавался много лет назад, но он все еще виден публично.

В этой теме и в этом предложено несколько примеров:
Определить, является ли тип словарем [дубликат]

но есть несколько несоответствий, поэтому я хочу поделиться своим решением

Краткий ответ:

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

Более длинный ответ:
Я считаю, что именно по этой причине люди совершают ошибки:

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

Допустим, у нас есть следующие типы:

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

и эти экземпляры:

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

поэтому, если мы будем использовать метод .IsAssignableFrom ():

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

мы не получим ни одного экземпляра

так что лучший способ - получить все интерфейсы и проверить, является ли какой-либо из них словарным интерфейсом:

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
1 голос
/ 23 сентября 2008

вы можете проверить, реализует ли он IDictionary . Вам просто нужно перечислить, используя класс DictionaryEntry .

0 голосов
/ 06 января 2010
if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType()))
{

}
0 голосов
/ 24 сентября 2008

Я считаю, что предупреждение на месте.

Когда вы проверяете, является ли объект «чем-то» тем или иным, вы переопределяете (часть) систему типов. За первым 'is a' часто быстро следует второй, и вскоре ваш код полон проверок типов, которые должны очень хорошо обрабатываться системой типов - по крайней мере, в объектно-ориентированном дизайне.

Конечно, я ничего не знаю о контексте вопроса. Я знаю 2000-строчный файл в нашей собственной кодовой базе, который обрабатывает 50 различных преобразований объекта в строку ...: (*

0 голосов
/ 23 сентября 2008

Вы могли бы быть немного более универсальным и спросить вместо этого, реализует ли он IDictionary. Тогда коллекция KeyValue будет продолжаться просто Objects.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...