基于现有.NET类型生成仅改名称的新类型解决EF Core动态建库失败问题
适用场景
解决EF Core动态添加模型创建多数据库时,类型与表结构缓存绑定导致的二次执行失败问题
实现方案
核心逻辑:通过.NET Reflection.Emit API 动态构建新类型,完整复制原类型的特性、属性、字段、继承关系等所有结构,仅修改类型名称,完全匹配需求。
完整实现代码
using System.Reflection; using System.Reflection.Emit; public static Type CreateNewType(Type originalType, string newTypeName) { // 定义独立的动态程序集和模块,避免冲突 var assemblyName = new AssemblyName($"{originalType.Assembly.GetName().Name}.Dynamic.{Guid.NewGuid():N}"); var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name!); // 定义新类型基础属性 var typeAttributes = originalType.Attributes; TypeBuilder typeBuilder; if (originalType.IsClass) { typeBuilder = moduleBuilder.DefineType(newTypeName, typeAttributes, originalType.BaseType); // 复制原类型所有实现接口 foreach (var interfaceType in originalType.GetInterfaces()) { typeBuilder.AddInterfaceImplementation(interfaceType); } } else if (originalType.IsValueType) { typeBuilder = moduleBuilder.DefineType(newTypeName, typeAttributes, typeof(ValueType)); } else { throw new NotSupportedException("仅支持类和值类型的复制生成"); } // 复制所有字段定义 foreach (var field in originalType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { typeBuilder.DefineField(field.Name, field.FieldType, field.Attributes); } // 复制所有属性及对应的get/set方法 foreach (var prop in originalType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) { var propBuilder = typeBuilder.DefineProperty(prop.Name, prop.Attributes, prop.PropertyType, prop.GetIndexParameters().Select(p => p.ParameterType).ToArray()); if (prop.GetMethod != null) { var getMethodBuilder = CopyMethod(prop.GetMethod, typeBuilder); propBuilder.SetGetMethod(getMethodBuilder); } if (prop.SetMethod != null) { var setMethodBuilder = CopyMethod(prop.SetMethod, typeBuilder); propBuilder.SetSetMethod(setMethodBuilder); } } // 复制所有自定义特性,确保EF Core映射规则完全一致 foreach (var attr in originalType.GetCustomAttributesData()) { var attributeBuilder = new CustomAttributeBuilder( attr.Constructor, attr.ConstructorArguments.Select(a => a.Value).ToArray(), attr.NamedArguments.Where(n => !n.IsField).Select(n => n.MemberInfo as PropertyInfo).ToArray(), attr.NamedArguments.Where(n => !n.IsField).Select(n => n.TypedValue.Value).ToArray(), attr.NamedArguments.Where(n => n.IsField).Select(n => n.MemberInfo as FieldInfo).ToArray(), attr.NamedArguments.Where(n => n.IsField).Select(n => n.TypedValue.Value).ToArray() ); typeBuilder.SetCustomAttribute(attributeBuilder); } return typeBuilder.CreateTypeInfo()!.AsType(); } // 辅助方法:复制方法定义 private static MethodBuilder CopyMethod(MethodInfo originalMethod, TypeBuilder typeBuilder) { var parameters = originalMethod.GetParameters(); var methodBuilder = typeBuilder.DefineMethod( originalMethod.Name, originalMethod.Attributes, originalMethod.CallingConvention, originalMethod.ReturnType, parameters.Select(p => p.ParameterType).ToArray() ); for (int i = 0; i < parameters.Length; i++) { methodBuilder.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name); } // 自动实现属性的get/set逻辑 if (originalMethod.IsSpecialName && (originalMethod.Name.StartsWith("get_") || originalMethod.Name.StartsWith("set_"))) { var fieldName = $"_{char.ToLower(originalMethod.Name[4])}{originalMethod.Name.Substring(5)}"; var fieldType = originalMethod.Name.StartsWith("get_") ? originalMethod.ReturnType : parameters[0].ParameterType; var field = typeBuilder.DefineField(fieldName, fieldType, FieldAttributes.Private); var il = methodBuilder.GetILGenerator(); if (originalMethod.Name.StartsWith("get_")) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, field); il.Emit(OpCodes.Ret); } else { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Stfld, field); il.Emit(OpCodes.Ret); } } return methodBuilder; }
使用示例
var oldType = someObject.GetType(); var type = CreateNewType(oldType, "newType");
注意事项
- 该实现默认完整复制EF Core模型映射需要的所有结构,生成的新类型和原类型逻辑完全一致,仅类型标识不同,可直接规避EF Core的模型缓存绑定问题
- 动态生成的程序集仅在内存中运行,不会生成本地文件,运行性能满足常规业务需求
- 若原类型包含复杂自定义方法、泛型参数、静态成员,可根据实际业务需求扩展CopyMethod方法的实现逻辑
内容的提问来源于stack exchange,提问作者Júlio Almeida
相关产品推荐
相关产品推荐

