You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Reflection.Emit/Sigil实现构造函数链时遇异常问题

解决Sigil创建链式构造函数时的"Not Supported Before Type Is Created"异常

咱先把问题根源说透:这个异常的核心是你在类型还没完成创建(没调用TypeBuilder.CreateType())时,就试图直接通过反射获取该类型的成员——比如你要在无参构造里调用的带参构造函数,这时候反射根本找不到还没生成的成员,自然就报错了。

下面是修正后的完整代码,我会把关键细节拆解开讲:

using System;
using System.Reflection;
using System.Reflection.Emit;
using Sigil.NonGeneric;

public class Program
{
    public static void Main()
    {
        var asmName = new AssemblyName("MyAssembly");
        var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
        var moduleBuilder = asmBuilder.DefineDynamicModule("MyModule");
        
        // 1. 先定义Test类型的TypeBuilder,这是所有成员的载体
        var typeBuilder = moduleBuilder.DefineType("Test", TypeAttributes.Public);

        // 2. 先定义带参构造函数的Sigil生成器
        var ctorWithArg = Emit.NewConstructor(typeBuilder, MethodAttributes.Public, new[] { typeof(string) });
        
        // 实现带参构造:先调用Object的无参构造(所有类的基类构造必须先调用),再返回
        ctorWithArg.LoadArgument(0); // 加载当前实例的this指针
        ctorWithArg.CallConstructor(typeof(object).GetConstructor(Type.EmptyTypes)); // 调用基类构造
        ctorWithArg.Return();
        
        // 3. 完成带参构造的IL生成,但此时类型还没创建,只是构造的逻辑定义好了
        ctorWithArg.CreateConstructor();

        // 4. 定义无参构造的Sigil生成器
        var ctorWithoutArg = Emit.NewConstructor(typeBuilder, MethodAttributes.Public, Type.EmptyTypes);
        
        // 关键修复:不要用反射找Test的带参构造,用Sigil的专属重载通过签名引用
        ctorWithoutArg.LoadArgument(0); // 加载this指针
        ctorWithoutArg.LoadConstant("arg1"); // 准备要传给带参构造的字符串参数
        // 通过参数类型签名匹配,引用当前TypeBuilder里的带参构造(Sigil会在类型创建时自动绑定)
        ctorWithoutArg.CallConstructor(typeBuilder, new[] { typeof(string) });
        ctorWithoutArg.Return();
        
        // 5. 完成无参构造的IL生成
        ctorWithoutArg.CreateConstructor();

        // 6. 最后一步!必须等所有成员都定义完,再创建类型
        var testType = typeBuilder.CreateType();

        // 测试验证
        var instance1 = Activator.CreateInstance(testType);
        var instance2 = Activator.CreateInstance(testType, "customArg");
        Console.WriteLine("两个实例都创建成功啦!");
    }
}

核心修复要点:

  • 成员定义顺序:先定义被依赖的带参构造,再定义依赖它的无参构造,确保签名信息存在。
  • 避免提前反射:绝对不能在CreateType()之前用typeBuilder.GetConstructor(...)去获取构造函数——这时候类型还没生成,反射根本拿不到。改用Sigil的CallConstructor(TypeBuilder, Type[])重载,它会在IL层面预留引用,等类型创建时再完成绑定。
  • 最后创建类型:typeBuilder.CreateType()必须放在所有成员(构造、方法、属性等)都定义完成之后,这一步才会把所有动态定义的成员正式绑定到类型上,完成整个类型的生成。

内容的提问来源于stack exchange,提问作者jacob1123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:16:45