16

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

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

我想做类似的事情:

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

有没有办法在运行时使用反射动态地做到这一点?我知道可以将反射与泛型类型一起使用并确定键/值参数,但我不确定在检索到这些值之后是否有办法完成其余的工作。

4

8 回答 8

13

检查它是否实现了 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。

于 2008-09-23T19:22:40.127 回答
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);
}
于 2008-09-23T19:27:55.417 回答
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())))

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

//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
于 2015-04-15T11:52:07.320 回答
1

您可以检查它是否实现了IDictionary。您只需要使用DictionaryEntry类进行枚举。

于 2008-09-23T19:23:03.590 回答
0

您可以更通用一点,而是询问它是否实现了IDictionary. 然后 KeyValue 集合将 contina plain Objects

于 2008-09-23T19:23:01.280 回答
0

我相信警告已经到位。

当您测试一个对象是否“是”某物时,您正在重新实现(部分)类型系统。第一个“is a”通常紧随其后的是第二个,很快你的代码就会充满类型检查,类型系统应该很好地处理这些检查——至少在面向对象的设计中是这样。

当然,我对这个问题的背景一无所知。我知道我们自己的代码库中有一个 2000 行的文件,它处理 50 个不同的对象到字符串的转换...... :(

于 2008-09-23T20:21:00.407 回答
0
if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType()))
{

}
于 2010-01-05T23:59:24.273 回答
0

我来自确定类型是否为字典,那里的答案都没有充分解决我的问题。

这里最接近的答案来自Lukas Klusis,但没有给出IsDictionary(Type type)方法。这是从他的回答中汲取灵感的方法:

private static Type[] dictionaryInterfaces = 
{
  typeof(IDictionary<,>),
  typeof(System.Collections.IDictionary),
  typeof(IReadOnlyDictionary<,>),
};

public static bool IsDictionary(Type type) 
{
   return dictionaryInterfaces
    .Any(dictInterface =>
        dictInterface == type || // 1
        (type.IsGenericType && dictInterface == type.GetGenericTypeDefinition()) || // 2
        type.GetInterfaces().Any(typeInterface => // 3
                                 typeInterface == dictInterface ||
                                 (typeInterface.IsGenericType && dictInterface == typeInterface.GetGenericTypeDefinition())));
}

// 1地址public System.Collections.IDictionary MyProperty {get; set;}

// 2地址public IDictionary<SomeObj, SomeObj> MyProperty {get; set;}

// 3(即第二个.Any)解决了type实现任何一种dictionaryInterfaces类型的任何场景。

其他答案的问题——假设他们解决了#3——是他们没有解决#1和#2。这是可以理解的,因为获取和检查属性的类型可能并不常见。但是,如果您像我一样,并且该场景您用例的一部分,那就去吧!

于 2021-06-22T04:24:23.067 回答