C# 自动映射自动创建createMap

C# 自动映射自动创建createMap,c#,automapper,C#,Automapper,我有一个服务正在调用另一个服务。这两个服务都使用“相同的类”。这些类的名称相同,属性相同,但名称空间不同,因此我需要使用AutoMapper从一个类型映射到另一个类型 不,这很简单,因为我所要做的就是CreateMap,但问题是我们有大约数百个类,我需要手动从中编写CreateMap,它的工作与我有关。没有任何自动CreateMap功能。因此,如果我说CreateMap(),那么AutoMaper将通过组织工作并找到所有类,并自动为这些类及其子类执行CreateMap 希望有一个简单的解决方案,

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

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


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

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; }
    }
}
[TestClass]
公共类AutoMapper_示例
{
[测试方法]
public void AutoMapper_DynamicMap()
{
Source Source=newsource{Id=1,Name=“Mr FooBar”};
Target=Mapper.DynamicMap(源);
arest.AreEqual(1,target.Id);
Assert.AreEqual(“Mr FooBar”,target.Name);
}
私有类目标
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
私有类源
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
}

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

var dto = Mapper.Map<FooDTO>
     (foo, opts => opts.CreateMissingTypeMaps = true);
如果要继续使用旧的静态API(不再推荐),也可以执行以下操作:

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

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

从Automapper 9.0版开始,删除了
CreateMissingTypeMaps
API。Automapper文档现在建议显式配置映射,手动或使用反射


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

public class MyProfile : Profile {
    CreateMissingTypeMaps = true;

    // Mappings...
}

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

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

今天,我在一些通用代码中也需要它。我试过这样的方法:

    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>();
private static IMapper CreateMapper()
{
返回新的MapperConfiguration(cfg=>FillMapperConfig(cfg,typeof(T1),typeof(T2)))
.CreateMapper();
}
私有静态void FillMapperConfig(IMapperConfigurationExpression cfg,类型T1,类型T2)
{
如果(T1==T2)
{
返回;
}
CreateMap(T1,T2);
foreach(T1.GetProperties()中的PropertyInfo PropertyInfo)
{
属性信息对应的属性=
T2.GetProperties()
.FirstOrDefault(p=>
p、 Name==propertyInfo.Name);
if(correspondingProperty!=null)
{
如果(propertyInfo.PropertyType.IsGenericType&&
对应的Property.PropertyType.IsGenericType)
{
FillMapperConfig(
cfg,
propertyInfo.PropertyType.GetGenericArguments()[0],
对应的Property.PropertyType.GetGenericArguments()[0]);
}
else if(propertyInfo.PropertyType.IsClass&&
对应的Property.PropertyType.IsClass)
{
FillMapperConfig(
cfg,
propertyInfo.PropertyType,
对应的属性。属性类型);
}
}
}
}
然后我可以这样做:

    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>();
IMapper mapper=CreateMapper();
这将创建一个从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; }
}
公共类ClassA{
公共int属性{get;set;}
公共类AsubProperty子属性{get;set;}
公共列表列表项{get;set;}
}
公共B类{
公共int属性{get;set;}
public ClassBSubProperty子属性{get;set;}
公共列表列表项{get;set;}
}
这将产生与IMapper等效的结果:

    new MapperConfiguration(cfg => {
        cfg.CreateMap<ClassA, ClassB>();
        cfg.CreateMap<ClassASubProperty, ClassBSubProperty>();
        cfg.CreateMap<ClassAListItem, ClassBListItem>()
    }).CreateMapper();
新的MapperConfiguration(cfg=>{
CreateMap();
CreateMap();
cfg.CreateMap()
}).CreateMapper();

有全局设置吗?@ChadKapatch,我不知道of@ThomasLevesque:不适用于我,给出如下错误,不包含“CreateMissingTypeMaps”的定义,并且找不到接受类型为的第一个参数的扩展方法。有什么想法吗?谢谢,@thomasleveque,但似乎CreateMapper()并没有被用来代替DynamicMap(),我的UserProfileVM model=AutoMapper.Mapper.DynamicMap(objUser);我想从这些中删除上面的错误…CreateMapper()对这些情况有帮助吗?@Bharat,对不起,我不明白你的问题是什么。您可能应该发布一个包含更多详细信息的完整问题。DynamicMap现在已过时,
Mapper.Map(foo,opts=>opts.CreateMissingTypeMaps=true)
是推荐的备选方案。只有这对我有效,在映射过程中设置它。初始化不起作用。仅供参考,CreateMissingTypeMaps属性应在Configure方法内设置。CreateMissingTypeMaps已过时:“9.0版中将删除对自动创建的映射的支持。您需要手动或使用反射显式配置映射。还考虑属性映射()。