Проверка, является ли объект словарем в C#

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

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

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

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

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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
15
0
13 795
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

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

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

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

Обновлено: Альтернатива, когда я понял, что 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.

Вы знаете, что IDictionary <TKey, TValue> на самом деле не реализует интерфейс IDictionary? Так что для универсальных словарей это не сработает. Посмотрите на msdn.microsoft.com/en-us/library/s4ys34ea.aspx

Greg Beech 23.09.2008 23:32

Кроме того, даже если это был Dictionary <TKey, TValue>, который действительно реализует IDictionary, тогда он реализует IEnumerable <KeyValuePair <TKey, TValue >>, поэтому я бы ожидал, что в случае с DictionaryEntry произойдет сбой.

Greg Beech 23.09.2008 23:39

Преобразование в DictionaryEntry не удается. До сих пор не нашел решения.

Bob Wintemberg 23.09.2008 23:50

Что ж, чтобы исправить Грега Бича, я просто открыл Dictionary <>, и он действительно реализует IDictionary, даже если IDictionary <> этого не делает. Забыл, что хотя использование метода индексации для получения DictionaryEntry будет работать, я не могу применить к нему SelectedItem. Исправлю, если найду решение без отражения.

Guvante 24.09.2008 04:58

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

Будьте осторожны со своей терминологией, упоминание неуниверсальных версий как универсальных, вероятно, сбивает с толку некоторых людей (я знаю, что всегда должен исправляться: P)

Guvante 23.09.2008 23:26

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

Ответ принят как подходящий

Должно получиться примерно следующее. Я написал это в поле для ответа, поэтому синтаксис может быть не совсем правильным, но я сделал его редактируемым в 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);
}

вероятно, было бы лучше использовать значение в штучной упаковке, чем использование отражения.

Darren Kopp 23.09.2008 23:33

Я не уверен, что вы имеете в виду? Вы не можете просто упаковать KeyValuePair <TKey, TValue>, чтобы извлечь из него значение.

Greg Beech 23.09.2008 23:38

Ваше решение сработало. Я изменил оператор if, чтобы продолжить, и просто протестировал "is IDictionary" (ваша часть typeof по какой-то причине не сработала). Я также изменил "typeof (KeyValuePair <,>)" на "listBox.SelectedItem"

Bob Wintemberg 24.09.2008 00:04

@Guvante Фактически, вы можете опустить параметры типа при использовании typeof с универсальным типом. Смотрите здесь: msdn.microsoft.com/en-us/library/b8ytshk6.aspx

Tim Goodman 23.10.2013 17:28

@TimGoodman: Это странно, я попробовал этот синтаксис и получил ошибку компиляции, удаление.

Guvante 24.10.2013 03:55

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

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

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

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

}

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

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

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

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

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

Другие вопросы по теме