.NET Core7中如何用AssemblyBuilder和TypeBuilder定义List<Foo>属性
解决方案
你的AddProperty方法核心逻辑本身是正确的,但使用时出现报错大概率是两个原因:一是动态生成的List字段未初始化导致空引用异常,二是如果Foo也是动态生成的类型,未确保其在创建泛型List类型前已完成类型构建。以下是修正后的完整实现方案:
1. 优化AddProperty方法
移除冗余指令,保留核心逻辑:
public static void AddProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType) { var fieldBuilder = typeBuilder.DefineField($"_{propertyName}", propertyType, FieldAttributes.Private); var propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null); // Get方法实现 var getMethod = typeBuilder.DefineMethod($"get_{propertyName}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes); var getIL = getMethod.GetILGenerator(); getIL.Emit(OpCodes.Ldarg_0); getIL.Emit(OpCodes.Ldfld, fieldBuilder); getIL.Emit(OpCodes.Ret); // Set方法实现 var setMethod = typeBuilder.DefineMethod($"set_{propertyName}", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, null, new[] { propertyType }); var setIL = setMethod.GetILGenerator(); setIL.Emit(OpCodes.Ldarg_0); setIL.Emit(OpCodes.Ldarg_1); setIL.Emit(OpCodes.Stfld, fieldBuilder); setIL.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getMethod); propertyBuilder.SetSetMethod(setMethod); }
2. 关键:为List字段添加初始化逻辑
动态类的字段默认值为null,直接调用List属性会触发空引用异常,需在无参构造函数中初始化List:
public static void AddListInitializer(TypeBuilder typeBuilder, FieldBuilder listField) { var listCtor = listField.FieldType.GetConstructor(Type.EmptyTypes); if (listCtor == null) throw new InvalidOperationException("List类型无可用的无参构造函数"); // 定义无参构造函数 var ctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes); var ctorIL = ctor.GetILGenerator(); // 调用基类构造函数 ctorIL.Emit(OpCodes.Ldarg_0); ctorIL.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); // 初始化List字段 ctorIL.Emit(OpCodes.Ldarg_0); ctorIL.Emit(OpCodes.Newobj, listCtor); ctorIL.Emit(OpCodes.Stfld, listField); ctorIL.Emit(OpCodes.Ret); }
3. 完整的动态程序集生成流程
示例1:生成带List属性的类型
// 定义程序集和模块 var assemblyName = new AssemblyName("DynamicListAssembly"); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, $"{assemblyName.Name}.dll"); // 定义动态类型 var typeBuilder = moduleBuilder.DefineType("DynamicType", TypeAttributes.Public | TypeAttributes.Class); // 添加List<string>属性 var listStringType = typeof(List<string>); AddProperty(typeBuilder, "Items", listStringType); // 获取字段并添加初始化逻辑 var fieldBuilder = typeBuilder.GetField("_Items", BindingFlags.NonPublic | BindingFlags.Instance); AddListInitializer(typeBuilder, fieldBuilder); // 完成类型创建并保存程序集 var dynamicType = typeBuilder.CreateType(); assemblyBuilder.Save($"{assemblyName.Name}.dll");
示例2:生成带自定义Foo类型的List属性(Foo为动态生成)
// 先创建自定义Foo类型 var fooTypeBuilder = moduleBuilder.DefineType("Foo", TypeAttributes.Public | TypeAttributes.Class); AddProperty(fooTypeBuilder, "Id", typeof(int)); AddProperty(fooTypeBuilder, "Name", typeof(string)); var fooType = fooTypeBuilder.CreateType(); // 构造List<Foo>泛型类型 var listFooType = typeof(List<>).MakeGenericType(fooType); // 添加List<Foo>属性到DynamicType AddProperty(typeBuilder, "FooItems", listFooType); var fooFieldBuilder = typeBuilder.GetField("_FooItems", BindingFlags.NonPublic | BindingFlags.Instance); AddListInitializer(typeBuilder, fooFieldBuilder); // 完成类型创建并保存 var dynamicType = typeBuilder.CreateType(); assemblyBuilder.Save($"{assemblyName.Name}.dll");
测试生成的程序集
// 加载程序集 var assembly = Assembly.LoadFrom("DynamicListAssembly.dll"); var dynamicType = assembly.GetType("DynamicType"); // 创建实例并使用属性 var instance = Activator.CreateInstance(dynamicType); var itemsProperty = dynamicType.GetProperty("Items"); var items = (List<string>)itemsProperty.GetValue(instance); items.Add("Test Item"); Console.WriteLine(items.Count); // 输出1
内容的提问来源于stack exchange,提问作者ilhan
相关产品推荐
相关产品推荐

