mardi 22 janvier 2019

.Net Reflection - GetInterfaces of generic type definition - strange behavior when checking equality

I recently had to do some reflection in .NET and stumbled upon a strange behavior while comparing generic type definitions.

I had to decide whether a type is an IDictionary<,> by extracting a Type object from a LINQ Expression so I was unable to use the is operator to decide it. Additionally, I had to ignore the type parameters, in other words, the only thing that was important is whether I was dealing with an IDictionary<,> of any key/value type.

I started out with the following:

// Just a placeholder, in my code I have no way of knowing that it
// is a Dictionary of string keys and string values or even that it
// is a dictionary at all.
typeof(Dictionary<string, string>)
    .GetGenericTypeDefinition()
    .GetInterfaces()
    .Any(i => i == typeof(IDictionary<,>))

I assumed that since I was reading the interfaces of a generic type definition I would get generic interface definitions. Even more strange is that when I pasted the above code to LINQPad it returned the following:

typeof(IDictionary<TKey,TValue>) // it appears here
typeof(ICollection<KeyValuePair<TKey,TValue>>) 
typeof(IEnumerable<KeyValuePair<TKey,TValue>>) 
typeof(IEnumerable) 
typeof(IDictionary) 
typeof(ICollection) 
typeof(IReadOnlyDictionary<TKey,TValue>) 
typeof(IReadOnlyCollection<KeyValuePair<TKey,TValue>>) 
typeof(ISerializable) 
typeof(IDeserializationCallback) 

Yet for some reason the comparison in the Any method did not succeed for any of these elements. However, if I get the generic type definitions for the interfaces themselves like so:

typeof(Dictionary<string, string>)
    .GetGenericTypeDefinition()
    .GetInterfaces()
    .Select(i => i.IsGenericType ? i.GetGenericTypeDefinition() : i)
    .Any(i => i == typeof(IDictionary<,>))

then it returns true like it should.

Why is that? Aren't the interfaces returned by the .GetInterfaces() method when called on a generic type definition generic interface definitions themselves already? If so, what's the explanation that when I inspect the returned interfaces in LINQPad they appear to be generic type definitions?





Aucun commentaire:

Enregistrer un commentaire