Тестирование, если объект является словарем в С#
Есть ли способ проверить, является ли объект словарем?
В методе, который я пытаюсь получить значение из выбранного элемента в списке. В некоторых случаях окно списка может быть привязано к словарю, но это не известно во время компиляции.
Я хотел бы сделать что-то похожее на это:
if (listBox.ItemsSource is Dictionary<??>)
{
KeyValuePair<??> pair = (KeyValuePair<??>)listBox.SelectedItem;
object value = pair.Value;
}
Есть ли способ сделать это динамически во время выполнения, используя отражение? Я знаю, что можно использовать отражение с типичными типами и определять параметры ключа/значения, но я не уверен, есть ли способ сделать остальное после получения этих значений.
Ответы
Ответ 1
Это должно быть что-то вроде следующего. Я написал это в поле ответа, поэтому синтаксис может быть не совсем прав, но я сделал его доступным для 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);
}
Ответ 2
Проверьте, реализует ли он 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 все время.
Ответ 3
Я знаю, что этот вопрос задавался много лет назад, но он все еще остается открытым.
Было несколько примеров, предложенных здесь в этой теме, и в этом:
Определите, является ли тип словарем [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
Ответ 4
вы можете проверить, реализует ли он IDictionary. Вам просто нужно перечислить класс DictionaryEntry.
Ответ 5
Вы можете быть немного более общим и спросить, если он реализует IDictionary
. Тогда коллекция KeyValue будет contina plain Objects
.
Ответ 6
Я считаю, что предупреждение находится на месте.
Когда вы проверяете, является ли объект "чем-то тем или иным", вы переопределяете (часть) систему типов. Первая "есть" часто быстро сопровождается второй, и вскоре ваш код заполнен проверками типов, которые должны быть очень хорошо обработаны системой типов - по крайней мере, в объектно-ориентированном дизайне.
Конечно, я ничего не знаю о контексте вопроса. Я знаю файл строки 2000 в нашей собственной базе кода, которая обрабатывает 50 разных объектов для преобразования строк...: (
Ответ 7
if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType()))
{
}