AutoMapper自动创建createMap

时间:2013-06-13 11:24:37

标签: c# automapper

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

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

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

5 个答案:

答案 0 :(得分:25)

在选项中将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
});

答案 1 :(得分: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; }
    }
}

答案 2 :(得分:3)

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

0.0.0.0/0

答案 3 :(得分:1)

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

public class Startup {
    //...
    public void ConfigureServices(IServiceCollection services) {
        //...
        services.AddAutoMapper(cfg => { cfg.CreateMissingTypeMaps = true; });
        //...
    }
    //...
}

答案 4 :(得分: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();