Testando se um objeto é um dicionário em C #

votos
14

Existe uma maneira de testar se um objeto é um dicionário?

Em um método que eu estou tentando obter um valor de um item selecionado em uma caixa lista. Em algumas circunstâncias, a caixa de lista pode ser ligado a um dicionário, mas isso não é conhecido em tempo de compilação.

Eu gostaria de fazer algo semelhante a isto:

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

Existe uma maneira de fazer isso dinamicamente em tempo de execução usando reflexão? Eu sei que é possível usar a reflexão com tipos genéricos e determinar os parâmetros de chave / valor, mas não tenho certeza se há uma maneira de fazer o resto depois esses valores são recuperados.

Publicado 23/09/2008 em 20:19
fonte usuário
Em outras línguas...                            


7 respostas

votos
13

Verifique para ver se ele implementa IDictionary.

Veja a definição de System.Collections.IDictionary para ver o que lhe dá.

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

EDIT: Alternativa quando percebi KeyValuePair de não passível de conversão para DictionaryEntry

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

Esta solução usa reflexão, mas, neste caso, você não tem que fazer o trabalho pesado, ListBox faz isso por você. Além disso, se você geralmente tem dicionários como fontes de dados que você pode ser capaz de evitar zerando ValueMember o tempo todo.

Respondeu 23/09/2008 em 20:22
fonte usuário

votos
10

Deve ser algo como o seguinte. Eu escrevi isso na caixa de resposta assim que a sintaxe pode não ser exatamente certo, mas eu fiz isso Wiki editável para que qualquer um pode corrigir-se.

if (listBox.ItemsSource.IsGenericType && 
    typeof(IDictionary<,>).IsAssignableFrom(listBox.ItemsSource.GetGenericTypeDefinition()))
{
    var method = typeof(KeyValuePair<,>).GetProperty("Value").GetGetMethod();
    var item = method.Invoke(listBox.SelectedItem, null);
}
Respondeu 23/09/2008 em 20:27
fonte usuário

votos
3

Eu sei que esta pergunta foi feita há muitos anos, mas ainda é visível publicamente.

Houve alguns exemplos aqui propostas neste tópico e neste:
Determinar se o tipo é dicionário [duplicado]

mas existem alguns desencontros, então eu quero compartilhar minha solução

Resposta curta:

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

Resposta mais longa:
Eu acredito que esta é a razão por que as pessoas cometem erros:

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

então vamos dizer que temos estes tipos:

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

e nesses casos:

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

por isso, se vamos usar o método .IsAssignableFrom ():

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

que não terá qualquer instância

assim melhor maneira é fazer com que todas as interfaces e verificar se algum deles é a interface dicionário:

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
Respondeu 15/04/2015 em 11:52
fonte usuário

votos
1

você pode verificar para ver se ele implementa IDictionary . Você só terá que enumerar sobre usando o DictionaryEntry classe.

Respondeu 23/09/2008 em 20:23
fonte usuário

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

}
Respondeu 06/01/2010 em 00:59
fonte usuário

votos
0

Eu acredito que um aviso está no lugar.

Quando você está testando se um objeto 'é um' algo isto ou aquilo, você está reimplementar (parte de) o sistema de tipos. O primeiro 'é um' é muitas vezes rapidamente seguido por um segundo, e logo seu código está cheio de verificações de tipo, que deve ser muito bem tratados pelo sistema tipo - pelo menos em um design orientado a objeto.

Claro, eu não sei nada sobre o contexto da pergunta. Eu sei um arquivo linha 2000, em nossa própria base de código que lida com 50 objeto diferente para conversões de cadeia ... :(

Respondeu 23/09/2008 em 21:21
fonte usuário

votos
0

Você poderia ser um pouco mais genérico e perguntar em vez se ele implementa IDictionary. Em seguida, a coleção KeyValue vai Contina simples Objects.

Respondeu 23/09/2008 em 20:23
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more