测试对象是否是C#中的字典

Bob*_*erg 15 c# reflection collections dictionary

有没有办法测试对象是否是字典?

在一个方法中,我试图从列表框中的选定项目中获取值.在某些情况下,列表框可​​能绑定到字典,但在编译时不知道.

我想做类似的事情:

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

有没有办法在运行时使用反射动态地执行此操作?我知道可以使用泛型类型的反射并确定键/值参数,但我不确定在检索这些值之后是否有办法完成其余的操作.

Guv*_*nte 13

检查它是否实现了IDictionary.

请参阅System.Collections.IDictionary的定义以查看它为您提供的内容.

if (listBox.ItemsSource is IDictionary)
{
    DictionaryEntry pair = (DictionaryEntry)listBox.SelectedItem;
    object value = pair.Value;
}
Run Code Online (Sandbox Code Playgroud)

编辑: 当我意识到KeyValuePair不能转换为DictionaryEntry时的替代方案

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

此解决方案使用反射,但在这种情况下,您不必执行繁琐的工作,ListBox会为您执行此操作.此外,如果您通常将字典作为数据源,则可以避免一直重置ValueMember.

  • 嗯,你知道IDictionary <TKey,TValue>实际上并没有实现IDictionary接口吗?所以这对通用词典不起作用.请查看http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx (4认同)

Gre*_*ech 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);
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我知道这个问题是多年前提出的,但它仍然公开可见。

本主题和本主题中提出的示例很少:
确定类型是否为字典 [重复]

但几乎没有不匹配,所以我想分享我的解决方案

简短的回答:

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())))
Run Code Online (Sandbox Code Playgroud)

更长的答案:
我相信这就是人们犯错误的原因:

//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
Run Code Online (Sandbox Code Playgroud)

所以假设我们有这些类型:

public class CustomReadOnlyDictionary : IReadOnlyDictionary<string, MyClass>
public class CustomGenericDictionary : IDictionary<string, MyClass>
public class CustomDictionary : IDictionary
Run Code Online (Sandbox Code Playgroud)

和这些实例:

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

所以如果我们将使用 .IsAssignableFrom() 方法:

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

我们不会得到任何实例

所以最好的方法是获取所有接口并检查它们中是否有一个是字典接口:

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
Run Code Online (Sandbox Code Playgroud)