Testing if an Object is a Dictionary in C#

后端 未结 7 1208
傲寒
傲寒 2020-12-06 10:21

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

7条回答
  •  甜味超标
    2020-12-06 10:54

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

    so let say we have these types:

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

    and these instances:

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

    so if we will use .IsAssignableFrom() method:

    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
    

提交回复
热议问题