Reflective Generic Detection
Trying to find out if a provided Type
is of a given generic type (with any generic types inside)
Let me Explain:
bool IsOfGenericType(Type baseType, Type sampleType)
{
/// ...
}
Such that:
IsOfGenericType(typeof(Dictionary<,>), typeof(Dictionary<string, int>)); // True
IsOfGenericType(typeof(IDictionary<,>), typeof(Dictionary<string, int>)); // True
IsOfGenericType(typeof(IList<>), typeof(Dictionary<string,int>)); // False
However, I played with some reflection in the intermediate window开发者_StackOverflow社区, here were my results:
typeof(Dictionary<,>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>).IsAssignableFrom(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsSubclassOf(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsInstanceOfType(typeof(Dictionary<,>))
false
typeof(Dictionary<,>).IsInstanceOfType(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsAssignableFrom(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsSubclassOf(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>) is typeof(Dictionary<string,int>)
Type expected
typeof(Dictionary<string,int>).IsAssignableFrom(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsSubclassOf(typeof(Dictionary<,>))
false
typeof(Dictionary<string,int>).IsInstanceOfType(typeof(Dictionary<,>))
false
typeof(Dictionary<,>).IsInstanceOfType(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsAssignableFrom(typeof(Dictionary<string,int>))
false
typeof(Dictionary<,>).IsSubclassOf(typeof(Dictionary<string,int>))
false
So now I'm at a loss because when you look at the base.Name on typeof(Dictionary) you get
Dictionary`2
Which is the same as typeof(Dictionary<,>).Name
At first I thought that this should work:
bool IsOfGenericType(Type baseType, Type sampleType) {
return baseType.IsAssignableFrom(sampleType.GetGenericTypeDefinition());
}
The GetGenericTypeDefinition method returns a version of the type without specified generic parameters. For example for type List<int>
it will give you List<>
.
But, unfortunately, this doesn't quite work, because the generic type definitions aren't assignable from each other (because they are not real types that you could use anywhere in your code). The IsAssignableFrom
method works only for actual types. This means that we need to make additional step and specify some type parameters back to the generic type definitions and then we can check whether they are assignable.
You can fill the type parameters with System.Object
and then compare them:
Type SpecifyObjectArgs(Type sample) {
var types = new Type[sample.GetGenericArguments().Length];
for(int i = 0; i < types.Length; i++) types[i] = typeof(System.Object);
return sample.MakeGenericType(types);
}
var baseWithObjs = SpecifyObjectArgs(baseType);
var sampleWithObjs = SpecifyObjectArgs(sampleType.GetGenericTypeDefinition());
baseWithObjs.IsAssignableFrom(sampleWithObjs);
This turns the generic type definition back to a normal type, so you'll get for example IList<Object>
and List<Object>
which can be tested easily using IsAssignableFrom
.
[There are still some limitations - see comments]
精彩评论