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

如何在C#中利用反射实现多库同结构模型的自动映射?

自动生成Mapster跨类库模型映射方案

核心思路

利用反射遍历目标命名空间下的所有模型类,根据类名匹配不同类库中的对应模型,再针对构造函数或属性赋值的场景自动生成Mapster映射规则,彻底替代手动维护。

实现步骤与代码示例

1. 加载程序集并筛选模型类型

先通过反射加载三个类库的程序集,提取出对应命名空间下的所有模型类:

// 加载三个类库的程序集,替换为实际的程序集名称
var assemblyA = Assembly.Load("LibraryA");
var assemblyB = Assembly.Load("LibraryB");
var assemblyC = Assembly.Load("LibraryC");

// 获取各命名空间下的模型类型,按类名存入字典方便匹配
var modelsA = assemblyA.GetTypes()
    .Where(t => t.Namespace == "LibraryA.Models" && t.IsClass && !t.IsAbstract)
    .ToDictionary(t => t.Name);
var modelsB = assemblyB.GetTypes()
    .Where(t => t.Namespace == "LibraryB.Models" && t.IsClass && !t.IsAbstract)
    .ToDictionary(t => t.Name);
var modelsC = assemblyC.GetTypes()
    .Where(t => t.Namespace == "LibraryC.Models" && t.IsClass && !t.IsAbstract)
    .ToDictionary(t => t.Name);

2. 通用映射配置方法

编写通用方法自动为匹配的模型对创建映射,优先使用构造函数初始化(参数与源属性匹配时),否则用属性赋值:

public static void AutoConfigureMapsterMappings()
{
    var config = TypeAdapterConfig.GlobalSettings;
    
    // 遍历LibraryA的模型,配置到LibraryB、LibraryC的映射
    foreach (var (modelName, sourceType) in modelsA)
    {
        if (modelsB.TryGetValue(modelName, out var targetTypeB))
        {
            ConfigureTypeMapping(config, sourceType, targetTypeB);
        }
        if (modelsC.TryGetValue(modelName, out var targetTypeC))
        {
            ConfigureTypeMapping(config, sourceType, targetTypeC);
        }
    }
    
    // 按需添加其他方向的映射(如B→A、C→B等)
}

private static void ConfigureTypeMapping(TypeAdapterConfig config, Type sourceType, Type targetType)
{
    // 优先查找匹配的构造函数:参数名、类型与源属性一致
    var matchedCtor = FindMatchingConstructor(sourceType, targetType);
    if (matchedCtor != null)
    {
        var mappingConfig = config.NewConfig(sourceType, targetType);
        var mapWithMethod = typeof(TypeAdapterConfig<,>)
            .MakeGenericType(sourceType, targetType)
            .GetMethod("MapWith", new[] { typeof(Expression<Func<,>>).MakeGenericType(sourceType, targetType) });
        
        var initExpr = CreateConstructorInitExpression(sourceType, targetType, matchedCtor);
        mapWithMethod.Invoke(mappingConfig, new[] { initExpr });
        return;
    }
    
    // 无匹配构造函数时,直接配置属性映射
    var propertyMapping = config.NewConfig(sourceType, targetType);
    var sourceProps = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
    foreach (var srcProp in sourceProps)
    {
        var targetProp = targetType.GetProperty(srcProp.Name, BindingFlags.Public | BindingFlags.Instance);
        if (targetProp != null && targetProp.CanWrite && srcProp.PropertyType == targetProp.PropertyType)
        {
            propertyMapping.Map(targetProp.Name, srcProp.Name);
        }
    }
}

private static ConstructorInfo FindMatchingConstructor(Type sourceType, Type targetType)
{
    var sourcePropsDict = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .ToDictionary(p => p.Name);
    
    foreach (var ctor in targetType.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
    {
        var parameters = ctor.GetParameters();
        // 验证所有构造参数都能在源类型找到同名同类型属性
        if (parameters.All(p => sourcePropsDict.TryGetValue(p.Name, out var prop) && prop.PropertyType == p.ParameterType))
        {
            return ctor;
        }
    }
    return null;
}

private static object CreateConstructorInitExpression(Type sourceType, Type targetType, ConstructorInfo constructor)
{
    var sourceParam = Expression.Parameter(sourceType, "src");
    var ctorParams = constructor.GetParameters()
        .Select(p => Expression.Property(sourceParam, p.Name))
        .ToArray();
    
    var newExpr = Expression.New(constructor, ctorParams);
    var lambdaType = typeof(Func<,>).MakeGenericType(sourceType, targetType);
    return Expression.Lambda(lambdaType, newExpr, sourceParam);
}

3. 使用方式

在程序启动阶段调用AutoConfigureMapsterMappings(),即可完成所有模型的自动映射配置,之后正常使用Adapt方法转换:

// 示例:LibraryA模型转LibraryB模型
var libraryBObj = libraryAObj.Adapt<LibraryB.Models.AnObject>();

扩展说明

  • 如果模型包含嵌套类,可在ConfigureTypeMapping中添加递归逻辑,自动处理嵌套模型的映射。
  • 可根据需求调整构造函数匹配规则(如忽略大小写),或添加自定义属性匹配逻辑。
  • 若程序集加载失败,可改用Assembly.LoadFrom指定程序集文件路径。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:23:27