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

基于现有.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:48:02