我有一个叫另一个服务的服务。这两个服务都使用“相同的类”。这些类被命名为相同且具有相同的属性但具有不同的命名空间,因此我需要使用AutoMapper从一种类型映射到另一种类型。
不,这很简单,因为我所要做的只是CreateMap<>
,但问题是我们有大约数百个类,我手动需要编写CreateMap<>
,并且它有效对我来说。没有任何自动CreateMap
功能。因此,如果我说CreateMap(),那么AutoMapper通过组织工作并查找所有类并自动为这些类及其子类等执行CreateMap
等等。
希望有一个简单的解决方案,或者我想一些反思可以解决它......
答案 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();