2.1配置(AutoMapper官方文档翻译)

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();
//     }
// }

在早期版本中,使用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针对一个特定的用例。但是您也可以在不更改类的情况下减小执行计划的大小。

你可以给每个成员全局地设置MapAtRuntimeMaxExecutionPlanDepth(默认为1,将它设置为零)。

这将通过用方法调用替换子对象的执行计划来减小执行计划的大小。编译会更快,但映射本身可能会更慢。搜索repo以获得更多细节,并使用分析器(profiler )来更好地理解效果。避免使用PreserveReferencesMaxDepth也有帮助。

原文链接

译者代码实现

github仓库地址
gitee仓库地址

你可能感兴趣的:(C#,automapper,c#)