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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/123181/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 14:37:03  来源:igfitidea点击:

Testing if an Object is a Dictionary in C#

提问by Bob Wintemberg

Is there a way to test if an object is a dictionary?

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

In a method I'm trying to get a value from a selected item in a list box. In some circumstances, the list box might be bound to a dictionary, but this isn't known at compile time.

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

I would like to do something similar to this:

我想做类似的事情:

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

Is there a way to do this dynamically at runtime using reflection? I know it's possible to use reflection with generic types and determine the key/value parameters, but I'm not sure if there's a way to do the rest after those values are retrieved.

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

采纳答案by Greg Beech

It should be something like the following. I wrote this in the answer box so the syntax may not be exactly right, but I've made it Wiki editable so anybody can fix up.

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

回答by Guvante

Check to see if it implements IDictionary.

检查它是否实现了 IDictionary。

See the definition of System.Collections.IDictionary to see what that gives you.

查看 System.Collections.IDictionary 的定义,看看它给了你什么。

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

EDIT:Alternative when I realized KeyValuePair's aren't castable to DictionaryEntry

编辑:当我意识到 KeyValuePair 不能投射到 DictionaryEntry 时的替代方法

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

This solution uses reflection, but in this case you don't have to do the grunt work, ListBox does it for you. Also if you generally have dictionaries as data sources you may be able to avoid reseting ValueMember all of the time.

此解决方案使用反射,但在这种情况下,您不必做繁重的工作,ListBox 会为您完成。此外,如果您通常将字典作为数据源,则可以避免始终重置 ValueMember。

回答by Frank Krueger

You could be a little more generic and ask instead if it implements IDictionary. Then the KeyValue collection will contina plain Objects.

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

回答by Darren Kopp

you can check to see if it implements IDictionary. You'll just have to enumerate over using the DictionaryEntryclass.

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

回答by xtofl

I believe a warning is at place.

我相信警告已经到位。

When you're testing if an object 'is a' something this or that, you're reimplementing (part of) the type system. The first 'is a' is often swiftly followed by a second one, and soon your code is full of type checks, which ought to be very well handled by the type system - at least in an object oriented design.

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

Of course, I know nothing of the context of the question. I do know a 2000 line file in our own codebase that handles 50 different object to String conversions... :(

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

回答by Randall Sutton

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

}

回答by Lukas Klusis

I know this question was asked many years ago, but it is still visible publicly.

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

There were few examples proposed here in this topic and in this one:
Determine if type is dictionary [duplicate]

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

but there are few mismatches, so I want to share my solution

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

Short answer:

简短的回答:

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

Longer answer:
I believe this is the reason why people make mistakes:

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

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

so let say we have these types:

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

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

and these instances:

和这些实例:

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

so if we will use .IsAssignableFrom() method:

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

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

we will not get any instance

我们不会得到任何实例

so best way is to get all interfaces and check if any of them is dictionary interface:

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

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