C#反射中如何判定嵌套类型泛型参数的声明来源
嵌套泛型类型的泛型参数归属判定
首先复现场景:
public class Class1<T> { public class Class2<U> { } }
对开放泛型类型typeof(Class1<>.Class2<>)调用GetGenericArguments()会返回长度为2的数组,依次对应外层的T和内层的U。在.NET Framework 2.0-4.x的反射实现中存在逻辑bug,两个泛型参数的DeclaringType属性都会错误返回Class2,无法直接通过该属性区分参数归属。
无需遍历全嵌套树的判定方案
反射有明确的参数排列规则:嵌套泛型类型的GetGenericArguments()返回数组,会按照从外到内的嵌套顺序排列泛型参数,当前类型自身声明的泛型参数永远排在数组末尾。
基于这个规则,不需要遍历整个嵌套类型树做逐层排除,仅需两步就能分离出当前类型自有的泛型参数:
- 取当前类型直接外层类型(
DeclaringType属性返回值)的泛型参数总数,这部分就是数组靠前位置、所有外层类型传入的泛型参数总个数 - 数组总长度减去外层参数总数,就是当前类型自身声明的泛型参数个数,取数组末尾对应长度的元素即可
示例代码:
Type openNestedType = typeof(Class1<>.Class2<>); Type[] allGenericArgs = openNestedType.GetGenericArguments(); int outerArgTotal = openNestedType.DeclaringType.GetGenericArguments().Length; int selfArgTotal = allGenericArgs.Length - outerArgTotal; // 所有来自外层嵌套类的泛型参数(即示例中的T) var outerArgs = allGenericArgs.Take(outerArgTotal); // 当前类型自身声明的泛型参数(即示例中的U) var selfArgs = allGenericArgs.TakeLast(selfArgTotal);
如果需要进一步判断每个外层参数具体属于哪一层嵌套类,才需要向上递归遍历DeclaringType链;如果只是需要区分参数是否属于当前类型,上述逻辑已经足够,不需要全树遍历。
高版本.NET的更简单实现
在.NET Core 1.0、.NET 5及以上版本中,上述反射bug已经被修复:外层类型声明的泛型参数的DeclaringType属性会正确返回对应的声明类型,直接判断genericArg.DeclaringType == currentType就能确认参数是否为当前类型自有。
注意事项
- 不要通过泛型参数名、标记自定义特性等方式判断归属,这类方案稳定性极差,遇到泛型参数重名、编译器自动生成的闭包/状态机类等场景会直接失效。
内容的提问来源于stack exchange,提问作者F-H
相关产品推荐
相关产品推荐

