2008-09-23 3 views
14

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

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

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

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

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

ответ

10

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

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

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

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

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

EDIT: Alternative, когда я понял, 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 все время.

+3

Um, вы знаете IDictionary фактически не реализует интерфейс IDictionary ? Таким образом, это не будет работать для общих словарей. Посмотрите на http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx – 2008-09-23 19:32:36

+0

Кроме того, даже если это был словарь , который реализует IDictionary, тогда он реализует IEnumerable >, поэтому я ожидаю, что case to DictionaryEntry для отказа. – 2008-09-23 19:39:05

+0

Конечно, я имел в виду «бросить в DictionaryEntry» выше. – 2008-09-23 19:44:31

0

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

0

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

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

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

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

} 
3

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

Существовали несколько примеров предложенных здесь в этой теме, и в этом одна:
Determine if type is dictionary [duplicate]

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

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

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