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

AutoMapper AddMaps重载未注册封闭泛型映射问题咨询

问题原因与解决方案

这是AutoMapper程序集扫描机制的特性限制,既不是配置疏漏也不是Bug。

核心原因

AutoMapper的AddMaps方法通过扫描指定程序集中所有继承自Profile的类型来加载映射配置,但它不会自动识别嵌套在未实例化泛型类型中的Profile类:

  • 你的MyGenericClassDto<T>是泛型类型,其内部的Mapping类属于泛型类型的嵌套成员,程序集扫描时AutoMapper无法发现这个Profile(因为泛型类型本身未被显式实例化的话,其嵌套类型不会被扫描器纳入范围)。
  • 而CreateMap是直接显式注册映射关系,完全绕过了程序集扫描逻辑,因此不受这个限制,能正常工作。

可行解决方案

方案1:将泛型DTO的Profile移到泛型类型外部

把映射配置类从泛型DTO内部移出,改为独立的非泛型Profile:

public record MyGenericClassDto<T>
{
    public T Id { get; init; } = default!;
    public string Name { get; init; } = null!;
}

// 独立的映射配置类
private class MyGenericClassDtoMapping : Profile
{
    public MyGenericClassDtoMapping() => CreateMap<MyClass, MyGenericClassDto<int>>();
}

这样AddMaps扫描程序集时就能正常识别到这个Profile。

方案2:显式注册泛型DTO的Profile

如果不想改动结构,可以直接用AddProfile显式指定要加载的泛型嵌套Profile:

var configuration = new MapperConfiguration(config => 
{
    config.AddMaps(Assembly.GetAssembly(typeof(MyClass)));
    // 显式添加泛型DTO的映射Profile
    config.AddProfile(typeof(MyGenericClassDto<int>.Mapping));
});

方案3:批量注册泛型映射(适用于多泛型参数场景)

如果需要支持多种Id类型的泛型DTO,可以在一个非泛型Profile中批量注册:

public class GenericDtoProfiles : Profile
{
    public GenericDtoProfiles()
    {
        CreateMap<MyClass, MyGenericClassDto<int>>();
        // 可以添加更多泛型参数的映射,比如long类型Id
        CreateMap<MyClass, MyGenericClassDto<long>>();
    }
}

修改后的测试示例(方案1)

调整后的代码可以让AddMaps的测试用例正常通过:

public class MyClass
{
    public int Id { get; set; }
    public string Name { get; set; } = null!;
}

public record MyClassDto 
{
    public int Id { get; init; }
    public string Name { get; init; } = null!;
    
    private class Mapping : Profile
    {
        public Mapping() => CreateMap<MyClass, MyClassDto>();
    }
}

public record MyGenericClassDto<T>
{
    public T Id { get; init; } = default!;
    public string Name { get; init; } = null!;
}

// 独立的泛型DTO映射配置
private class MyGenericClassDtoMapping : Profile
{
    public MyGenericClassDtoMapping() => CreateMap<MyClass, MyGenericClassDto<int>>();
}

public class MappingTests
{
    [Test]
    [TestCase(typeof(MyClass), typeof(MyClassDto))]
    [TestCase(typeof(MyClass), typeof(MyGenericClassDto<int>))]
    public void ShouldSupportMappingFromSourceToDestination_AddMaps(
        Type source, 
        Type destination)
    {
        var instance = GetInstanceOf(source);
        var configuration = new MapperConfiguration(config => 
            config.AddMaps(Assembly.GetAssembly(typeof(MyClass))));
        var mapper = configuration.CreateMapper();

        mapper.Map(instance, source, destination);
    }
    
    // 原CreateMap测试保持不变
    [Test]
    [TestCase(typeof(MyClass), typeof(MyClassDto))]
    [TestCase(typeof(MyClass), typeof(MyGenericClassDto<int>))]
    public void ShouldSupportMappingFromSourceToDestination_CreateMap(
        Type source, 
        Type destination)
    {
        var instance = GetInstanceOf(source);
        var config = new MapperConfiguration(cfg => 
            cfg.CreateMap(source, destination));
        var mapper = new Mapper(config);

        mapper.Map(instance, source, destination);
    }

    private static object GetInstanceOf(Type type) =>
        type.GetConstructor(Type.EmptyTypes) != null 
            ? Activator.CreateInstance(type)! :
            RuntimeHelpers.GetUninitializedObject(type);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 01:48:37