开发者

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]

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜