使用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
相关产品推荐
相关产品推荐

