Configuration
创建一个MapperConfiguration
实例并通过构造函数初始化配置:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo, Bar>();
cfg.AddProfile<FooProfile>();
});
MapperConfiguration
实例可以静态地存储在静态字段或依赖注入容器中。一旦创建,就不能更改/修改。
var configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo, Bar>();
cfg.AddProfile<FooProfile>();
});
从9.0开始,静态API不再可用。
配置文件(Profile)实例
使用配置文件是组织映射配置的一个良好实践。创建一个从Profile
继承的类,并将配置放入构造函数中:
// 这是从版本5开始的方法
public class OrganizationProfile : Profile
{
public OrganizationProfile()
{
CreateMap<Foo, FooDto>();
// 在这使用CreateMap...等(Profile方法与configuration方法相同)
}
}
// 这是已经废弃了的用于版本 4.x - 到 5.0 的方法:
// public class OrganizationProfile : Profile
// {
// protected override void Configure()
// {
// CreateMap<Foo, FooDto>();
// }
// }
在早期版本中,使用Configure方法代替构造函数。从版本5开始,Configure()已经过时了。它将在6.0中被删除。
配置文件中的配置只适用于配置文件中的映射。应用于根配置的配置将应用于创建的所有映射。
程序集扫描的自动配置
配置文件可以通过多种方式添加到主映射器配置中,或者直接添加:
cfg.AddProfile<OrganizationProfile>();
cfg.AddProfile(new OrganizationProfile());
或者通过自动扫描配置文件:
// 扫描程序集中所有的 profiles
// 通过使用程序集实体的:
var config = new MapperConfiguration(cfg => {
cfg.AddMaps(myAssembly);
});
var configuration = new MapperConfiguration(cfg => cfg.AddMaps(myAssembly));
// 通过使用程序集的名称:
var configuration = new MapperConfiguration(cfg =>
cfg.AddMaps(new [] {
"Foo.UI",
"Foo.Core"
});
);
// Or marker types for assemblies:
var configuration = new MapperConfiguration(cfg =>
cfg.AddMaps(new [] {
typeof(HomeController),
typeof(Entity)
});
);
AutoMapper将扫描指定的程序集,查找从Profile继承的类,并将它们添加到配置中。
命名约定(Naming Conventions)
可以设置源和目标命名约定
var configuration = new MapperConfiguration(cfg => {
cfg.SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance;
cfg.DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance;
});
这将把以下属性相互映射:
property_name -> PropertyName
您也可以设置每个配置文件
public class OrganizationProfile : Profile
{
public OrganizationProfile()
{
SourceMemberNamingConvention = LowerUnderscoreNamingConvention.Instance;
DestinationMemberNamingConvention = PascalCaseNamingConvention.Instance;
//Put your CreateMap... Etc.. here
}
}
如果不需要命名约定,可以使用
ExactMatchNamingConvention
替换字符
还可以在成员名匹配期间替换源成员中的单个字符或整个单词:
public class Source
{
public int Value { get; set; }
public int Ävíator { get; set; }
public int SubAirlinaFlight { get; set; }
}
public class Destination
{
public int Value { get; set; }
public int Aviator { get; set; }
public int SubAirlineFlight { get; set; }
}
我们想要替换单个字符,或者翻译一个单词:
var configuration = new MapperConfiguration(c =>
{
c.ReplaceMemberName("Ä", "A");
c.ReplaceMemberName("í", "i");
c.ReplaceMemberName("Airlina", "Airline");
});
识别前/后缀
有时源/目标属性会有共同的前缀/后缀,这会导致不得不做一堆自定义成员映射,因为名字不匹配。为了解决这个问题,可以识别前缀/后缀:
public class Source {
public int frmValue { get; set; }
public int frmValue2 { get; set; }
}
public class Dest {
public int Value { get; set; }
public int Value2 { get; set; }
}
var configuration = new MapperConfiguration(cfg => {
cfg.RecognizePrefixes("frm");
cfg.CreateMap<Source, Dest>();
});
configuration.AssertConfigurationIsValid();
默认情况下,AutoMapper识别前缀" Get ",如果你需要清除前缀:
var configuration = new MapperConfiguration(cfg => {
cfg.ClearPrefixes();
cfg.RecognizePrefixes("tmp");
});
配置的可见性
默认情况下,AutoMapper只识别public成员。它可以映射到私有setter,但如果整个属性都是私有/内部的,它将跳过内部/私有方法和属性。要指示AutoMapper识别具有其他可见性的成员,覆盖默认过滤器ShouldMapField
和/或Shouldmproperty
:
var configuration = new MapperConfiguration(cfg =>
{
// map properties with public or internal getters
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.CreateMap<Source, Destination>();
});
Map配置现在将识别内部/私有成员。
配置编译
因为表达式编译可能会占用一些资源,所以AutoMapper会在第一个映射上惰性地编译类型映射计划(译者注:调用的时候才编译映射)。然而,这种行为并不总是理想的,所以你可以告诉AutoMapper直接编译它的映射:
var configuration = new MapperConfiguration(cfg => {});
configuration.CompileMappings();
对于几百个映射,这可能需要几秒钟。如果花费的时间太长,可能是你有一些非常大的执行计划。
编译时间长
编译时间随着执行计划的大小而增加,这取决于属性的数量及其复杂性。理想情况下,您将修复您的模型,以便您有许多小型的DTO,每个DTO针对一个特定的用例。但是您也可以在不更改类的情况下减小执行计划的大小。
你可以给每个成员全局地设置MapAtRuntime
或MaxExecutionPlanDepth
(默认为1,将它设置为零)。
这将通过用方法调用替换子对象的执行计划来减小执行计划的大小。编译会更快,但映射本身可能会更慢。搜索repo以获得更多细节,并使用分析器(profiler )来更好地理解效果。避免使用PreserveReferences
和MaxDepth
也有帮助。