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

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

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

我想做类似的事情:

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

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

它应该类似于以下内容。 我在答案框中写了这个,所以语法可能不完全正确,但我已经将它编辑为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); } 

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

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

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

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

但是很少有不匹配,所以我想分享我的解决方案

简短回答:

 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).IsAssignableFrom(typeof(IDictionary)); // true typeof(IDictionary).IsAssignableFrom(typeof(Dictionary)); // true typeof(IDictionary<,>).IsAssignableFrom(typeof(Dictionary<,>)); // false!! in contrast with above line this is little bit unintuitive 

所以我们说这些类型:

 public class CustomReadOnlyDictionary : IReadOnlyDictionary public class CustomGenericDictionary : IDictionary public class CustomDictionary : IDictionary 

和这些实例:

 var dictionaries = new object[] { new Dictionary(), new ReadOnlyDictionary(new Dictionary()), 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 

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

您可能会更加通用,而是询问它是否实现了IDictionary 。 然后KeyValue集合将连接普通Objects

我相信会发出警告。

当你测试一个对象’是’这个或那个’时,你正在重新实现(部分)类型系统。 第一个’是a’通常会迅速跟随第二个,很快你的代码就会充满类型检查,类型系统应该很好地处理 – 至少在面向对象的设计中。

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

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