22

我有一个正在调用另一个服务的服务。这两项服务都使用“相同的类”。这些类的名称相同并且具有相同的属性但具有不同的命名空间,因此我需要使用 AutoMapper 从一种类型映射到另一种类型。

不,这很简单,因为我所要做的就是 . CreateMap<>,但问题是我们有大约数百个类,我需要手动编写CreateMap<>from,并且它与我有关。没有自动CreateMap功能。因此,如果我说 CreateMap() 那么 AutoMapper 通过组织工作并找到所有类并自动CreateMap为这些类及其子类等执行...</p>

希望有一个简单的解决方案,或者我想一些反思可以解决它......

4

5 回答 5

31

只需CreateMissingTypeMaps在选项中设置为 true:

var dto = Mapper.Map<FooDTO>
     (foo, opts => opts.CreateMissingTypeMaps = true);

如果您需要经常使用它,请将 lambda 存储在委托字段中:

static readonly Action<IMappingOperationOptions> _mapperOptions =
    opts => opts.CreateMissingTypeMaps = true;

...

var dto = Mapper.Map<FooDTO>(foo, _mapperOptions);

更新:

上述方法在 AutoMapper 的最新版本中不再适用。

相反,您应该创建一个CreateMissingTypeMaps设置为 true 的映射器配置,并从此配置创建一个映射器实例:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMissingTypeMaps = true;
    // other configurations
});
var mapper = config.CreateMapper();

如果你想继续使用旧的静态 API(不再推荐),你也可以这样做:

Mapper.Initialize(cfg =>
{
    cfg.CreateMissingTypeMaps = true;
    // other configurations
});

更新 2 - Automapper 9 及更高版本:

从 Automapper 9.0 版开始,该CreateMissingTypeMapsAPI 已被删除。Automapper 文档现在建议手动或使用反射显式配置地图。

https://docs.automapper.org/en/stable/9.0-Upgrade-Guide.html#automapper-no-longer-creates-maps-automatically-createmissingtypemaps-and-conventions

于 2014-05-01T00:10:02.570 回答
6

CreateMissingTypeMaps 可以在您的个人资料中设置。但是,建议为每个映射显式使用 CreateMap 并在每个配置文件的单元测试中调用 AssertConfigurationIsValid 以防止出现静默错误。

public class MyProfile : Profile {
    CreateMissingTypeMaps = true;

    // Mappings...
}
于 2016-06-12T14:41:58.237 回答
4

AutoMapper 有一个您可以使用的 DynamicMap 方法:这里有一个示例单元测试来说明它。

[TestClass]
public class AutoMapper_Example
{
    [TestMethod]
    public void AutoMapper_DynamicMap()
    {
        Source source = new Source {Id = 1, Name = "Mr FooBar"};

        Target target = Mapper.DynamicMap<Target>(source);

        Assert.AreEqual(1, target.Id);
        Assert.AreEqual("Mr FooBar", target.Name);
    }

    private class Target
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    private class Source
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
于 2013-06-13T12:34:17.333 回答
1

CreateMissingTypeMaps选项设置为 true。AutoMapper.Extensions.Microsoft.DependencyInjection这是ASP.NET Core 的package示例:

public class Startup {
    //...
    public void ConfigureServices(IServiceCollection services) {
        //...
        services.AddAutoMapper(cfg => { cfg.CreateMissingTypeMaps = true; });
        //...
    }
    //...
}
于 2018-09-07T07:01:34.003 回答
0

今天我在一些通用代码中也需要这个。我试过这样的事情:

    private static IMapper CreateMapper<T1, T2>()
    {
        return new MapperConfiguration(cfg => FillMapperConfig(cfg, typeof(T1), typeof(T2)))
            .CreateMapper();
    }

    private static void FillMapperConfig(IMapperConfigurationExpression cfg, Type T1, Type T2)
    {
        if (T1 == T2)
        {
            return;
        }

        cfg.CreateMap(T1, T2);

        foreach (PropertyInfo propertyInfo in T1.GetProperties())
        {
            PropertyInfo correspondingProperty =
                T2.GetProperties()
                    .FirstOrDefault(p =>
                        p.Name == propertyInfo.Name);

            if (correspondingProperty != null)
            {
                if (propertyInfo.PropertyType.IsGenericType && 
                    correspondingProperty.PropertyType.IsGenericType)
                {
                    FillMapperConfig(
                        cfg,
                        propertyInfo.PropertyType.GetGenericArguments()[0],
                        correspondingProperty.PropertyType.GetGenericArguments()[0]);
                }
                else if (propertyInfo.PropertyType.IsClass &&
                    correspondingProperty.PropertyType.IsClass)
                {
                    FillMapperConfig(
                        cfg,
                        propertyInfo.PropertyType,
                        correspondingProperty.PropertyType);
                }
            }
        }
    }

然后我可以做这样的事情:

   IMapper mapper = CreateMapper<ClassA, ClassB>();

如果 ClassA 和 ClassB 的所有子属性具有相同的名称并递归地用于子子属性,则会创建从 ClassA 到 ClassB 的映射。

例子:

public class ClassA {
    public int IntProperty { get; set; }

    public ClassASubProperty SubProperty { get; set; }

    public List<ClassAListItem> ListItems { get; set; }
}

public class ClassB {
    public int IntProperty { get; set; }

    public ClassBSubProperty SubProperty { get; set; }

    public List<ClassBListItem> ListItems { get; set; }
}

这应该会产生等效的 IMapper:

    new MapperConfiguration(cfg => {
        cfg.CreateMap<ClassA, ClassB>();
        cfg.CreateMap<ClassASubProperty, ClassBSubProperty>();
        cfg.CreateMap<ClassAListItem, ClassBListItem>()
    }).CreateMapper();
于 2021-03-17T16:08:04.180 回答