如何从封闭泛型类型获取返回类型为开放泛型的字段定义?
解决.NET玩具编译器中ValueTuple字段IL生成问题
核心思路
问题根源在于你直接使用封闭泛型类型的FieldInfo生成IL,它会绑定到具体类型(比如int32),但C#编译器实际是引用开放泛型类型的字段定义,让CLR在运行时自动解析为封闭泛型的对应字段,这样IL中会保留泛型参数占位符(!0、!1等)。
具体实现步骤
获取开放泛型类型定义
从你的封闭泛型元组类型(比如ValueTuple<int, int, int>)获取其泛型定义(即开放泛型ValueTuple<,,>):Type closedTupleType = typeof(ValueTuple<int, int, int>); Type openTupleType = closedTupleType.GetGenericTypeDefinition();从开放泛型类型获取字段定义
直接从开放泛型类型中获取对应的ItemN字段,这些字段的FieldType是泛型参数占位符(而非具体类型):FieldInfo openItem1Field = openTupleType.GetField("Item1")!; FieldInfo openItem2Field = openTupleType.GetField("Item2")!; FieldInfo openItem3Field = openTupleType.GetField("Item3")!;使用开放字段生成IL
在ILGenerator中,直接使用这些开放泛型的FieldInfo来生成ldfld指令。此时栈上必须是封闭泛型元组的实例,CLR会自动将开放字段解析为封闭类型的对应字段,生成的IL会保留泛型参数占位符:// 假设栈顶已经是封闭泛型元组实例 ilGenerator.Emit(OpCodes.Ldfld, openItem1Field);
为什么之前的尝试无效?
你之前直接使用封闭泛型的FieldInfo,它的FieldType已经被实例化为具体类型(比如int32),所以生成的ldfld指令会硬编码具体类型,导致运行时找不到匹配的字段(因为元组的字段定义本质上是在开放泛型中,封闭泛型的字段是其实例化后的版本,但元数据中引用的是开放泛型的字段定义)。
而使用开放泛型的FieldInfo生成IL时,CLR会在运行时根据当前的泛型上下文(封闭元组实例)解析字段,这样IL中的返回类型就会显示为泛型参数!0,和C#编译器生成的结果一致。
内容的提问来源于stack exchange,提问作者Jonas _
相关产品推荐
相关产品推荐

