反射通用检测

时间:2010-05-13 21:02:36

标签: c# .net generics reflection

试图找出提供的Type是否属于给定的泛型类型(内部有任何泛型类型)

让我解释一下:

bool IsOfGenericType(Type baseType, Type sampleType)
{
    /// ...
}

这样:

IsOfGenericType(typeof(Dictionary<,>), typeof(Dictionary<string, int>)); // True
IsOfGenericType(typeof(IDictionary<,>), typeof(Dictionary<string, int>)); // True
IsOfGenericType(typeof(IList<>), 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
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)上的base.Name时,你得到了

Dictionary`2

typeof(Dictionary<,>).Name

相同

1 个答案:

答案 0 :(得分:3)

起初我认为这应该有效:

bool IsOfGenericType(Type baseType, Type sampleType) { 
  return baseType.IsAssignableFrom(sampleType.GetGenericTypeDefinition());
} 

GetGenericTypeDefinition method返回没有指定通用参数的类型版本。例如,对于List<int>类型,它会为您提供List<>

但是,遗憾的是,这并不常用,因为泛型类型定义不能彼此分配(因为它们不是您可以在代码中的任何位置使用的实际类型)。 IsAssignableFrom方法仅适用于实际类型。这意味着我们需要进行额外的步骤并将一些类型参数指定回通用类型定义,然后然后我们可以检查它们是否可分配。

您可以使用System.Object填充类型参数,然后进行比较:

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

这会将泛型类型定义恢复为普通类型,因此您将获得IList<Object>List<Object>,可以使用IsAssignableFrom轻松测试。

[仍有一些限制 - 见评论]