C# AutoMapper 使用方法總結(jié)
本文基于 AutoMapper 9.0.0
AutoMapper 是一個(gè)對(duì)象-對(duì)象映射器,可以將一個(gè)對(duì)象映射到另一個(gè)對(duì)象。
官網(wǎng)地址:http://automapper.org/
官方文檔:https://docs.automapper.org/en/latest/
1 入門例子
public class Foo { public int ID { get; set; } public string Name { get; set; } } public class FooDto { public int ID { get; set; } public string Name { get; set; } } public void Map() { var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>()); var mapper = config.CreateMapper(); Foo foo = new Foo { ID = 1, Name = "Tom" }; FooDto dto = mapper.Map<FooDto>(foo); }
2 注冊(cè)
在使用 Map
方法之前,首先要告訴 AutoMapper 什么類可以映射到什么類。
var config = new MapperConfiguration(cfg => cfg.CreateMap<Foo, FooDto>());
每個(gè) AppDomain 只能進(jìn)行一次配置。這意味著放置配置代碼的最佳位置是在應(yīng)用程序啟動(dòng)中,例如 ASP.NET 應(yīng)用程序的 Global.asax 文件。
從 9.0 開始 Mapper.Initialize
方法就不可用了。
2.1 Profile
Profile
是組織映射的另一種方式。新建一個(gè)類,繼承 Profile
,并在構(gòu)造函數(shù)中配置映射。
public class EmployeeProfile : Profile { public EmployeeProfile() { CreateMap<Employee, EmployeeDto>(); } } var config = new MapperConfiguration(cfg => { cfg.AddProfile<EmployeeProfile>(); });
Profile
內(nèi)部的配置僅適用于 Profile
內(nèi)部的映射。應(yīng)用于根配置的配置適用于所有創(chuàng)建的映射。
AutoMapper 也可以在指定的程序集中掃描從 Profile
繼承的類,并將其添加到配置中。
var config = new MapperConfiguration(cfg => { // 掃描當(dāng)前程序集 cfg.AddMaps(System.AppDomain.CurrentDomain.GetAssemblies()); // 也可以傳程序集名稱(dll 名稱) cfg.AddMaps("LibCoreTest"); });
3 配置
3.1 命名約定
默認(rèn)情況下,AutoMapper 基于相同的字段名映射,并且是 不區(qū)分大小寫 的。
但有時(shí),我們需要處理一些特殊的情況。
SourceMemberNamingConvention
表示源類型命名規(guī)則DestinationMemberNamingConvention
表示目標(biāo)類型命名規(guī)則
LowerUnderscoreNamingConvention
和 PascalCaseNamingConvention
是 AutoMapper 提供的兩個(gè)命名規(guī)則。前者命名是小寫并包含下劃線,后者就是帕斯卡命名規(guī)則(每個(gè)單詞的首字母大寫)。
我的理解,如果源類型和目標(biāo)類型分別采用了 蛇形命名法 和 駝峰命名法,那么就需要指定命名規(guī)則,使其能正確映射。
public class Foo { public int Id { get; set; } public string MyName { get; set; } } public class FooDto { public int ID { get; set; } public string My_Name { get; set; } } public void Map() { var config = new MapperConfiguration(cfg => { cfg.CreateMap<Foo, FooDto>(); cfg.SourceMemberNamingConvention = new PascalCaseNamingConvention(); cfg.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention(); }); var mapper = config.CreateMapper(); Foo foo = new Foo { Id = 2, MyName = "Tom" }; FooDto dto = mapper.Map<FooDto>(foo); }
3.2 配置可見性
默認(rèn)情況下,AutoMapper 僅映射 public
成員,但其實(shí)它是可以映射到 private
屬性的。
var config = new MapperConfiguration(cfg => { cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.SetMethod.IsPrivate; cfg.CreateMap<Source, Destination>(); });
需要注意的是,這里屬性必須添加 private set
,省略 set
是不行的。
3.3 全局屬性/字段過濾
默認(rèn)情況下,AutoMapper 嘗試映射每個(gè)公共屬性/字段。以下配置將忽略字段映射。
var config = new MapperConfiguration(cfg => { cfg.ShouldMapField = fi => false; });
3.4 識(shí)別前綴和后綴
var config = new MapperConfiguration(cfg => { cfg.RecognizePrefixes("My"); cfg.RecognizePostfixes("My"); }
3.5 替換字符
var config = new MapperConfiguration(cfg => { cfg.ReplaceMemberName("Ä", "A"); });
這功能我們基本上用不上。
4 調(diào)用構(gòu)造函數(shù)
有些類,屬性的 set
方法是私有的。
public class Commodity { public string Name { get; set; } public int Price { get; set; } } public class CommodityDto { public string Name { get; } public int Price { get; } public CommodityDto(string name, int price) { Name = name; Price = price * 2; } }
AutoMapper 會(huì)自動(dòng)找到相應(yīng)的構(gòu)造函數(shù)調(diào)用。如果在構(gòu)造函數(shù)中對(duì)參數(shù)做一些改變的話,其改變會(huì)反應(yīng)在映射結(jié)果中。如上例,映射后 Price
會(huì)乘 2。
禁用構(gòu)造函數(shù)映射:
public class Commodity { public string Name { get; set; } public int Price { get; set; } } public class CommodityDto { public string Name { get; } public int Price { get; } public CommodityDto(string name, int price) { Name = name; Price = price * 2; } }
AutoMapper 會(huì)自動(dòng)找到相應(yīng)的構(gòu)造函數(shù)調(diào)用。如果在構(gòu)造函數(shù)中對(duì)參數(shù)做一些改變的話,其改變會(huì)反應(yīng)在映射結(jié)果中。如上例,映射后 Price 會(huì)乘 2。
禁用構(gòu)造函數(shù)映射:
var config = new MapperConfiguration(cfg => cfg.DisableConstructorMapping());
禁用構(gòu)造函數(shù)映射的話,目標(biāo)類要有一個(gè)無參構(gòu)造函數(shù)。
5 數(shù)組和列表映射
數(shù)組和列表的映射比較簡單,僅需配置元素類型,定義簡單類型如下:
public class Source { public int Value { get; set; } } public class Destination { public int Value { get; set; } }
映射:
var config = new MapperConfiguration(cfg => { cfg.CreateMap<Source, Destination>(); }); IMapper mapper = config.CreateMapper(); var sources = new[] { new Source { Value = 5 }, new Source { Value = 6 }, new Source { Value = 7 } }; IEnumerable<Destination> ienumerableDest = mapper.Map<Source[], IEnumerable<Destination>>(sources); ICollection<Destination> icollectionDest = mapper.Map<Source[], ICollection<Destination>>(sources); IList<Destination> ilistDest = mapper.Map<Source[], IList<Destination>>(sources); List<Destination> listDest = mapper.Map<Source[], List<Destination>>(sources); Destination[] arrayDest = mapper.Map<Source[], Destination[]>(sources);
具體來說,支持的源集合類型包括:
- IEnumerable
- IEnumerable
- ICollection
- ICollection
- IList
- IList
- List
- Arrays
映射到現(xiàn)有集合時(shí),將首先清除目標(biāo)集合。如果這不是你想要的,請(qǐng)查看AutoMapper.Collection。
5.1 處理空集合
映射集合屬性時(shí),如果源值為 null
,則 AutoMapper 會(huì)將目標(biāo)字段映射為空集合,而不是 null
。這與 Entity Framework 和 Framework Design Guidelines 的行為一致,認(rèn)為 C# 引用,數(shù)組,List,Collection,Dictionary 和 IEnumerables 永遠(yuǎn)不應(yīng)該為 null
。
5.2 集合中的多態(tài)
這個(gè)官方的文檔不是很好理解。我重新舉個(gè)例子。實(shí)體類如下:
public class Employee { public int ID { get; set; } public string Name { get; set; } } public class Employee2 : Employee { public string DeptName { get; set; } } public class EmployeeDto { public int ID { get; set; } public string Name { get; set; } } public class EmployeeDto2 : EmployeeDto { public string DeptName { get; set; } }
數(shù)組映射代碼如下:
var config = new MapperConfiguration(cfg => { cfg.CreateMap<Employee, EmployeeDto>().Include<Employee2, EmployeeDto2>(); cfg.CreateMap<Employee2, EmployeeDto2>(); }); IMapper mapper = config.CreateMapper(); var employees = new[] { new Employee { ID = 1, Name = "Tom" }, new Employee2 { ID = 2, Name = "Jerry", DeptName = "R & D" } }; var dto = mapper.Map<Employee[], EmployeeDto[]>(employees);
可以看到,映射后,dto 中兩個(gè)元素的類型,一個(gè)是 EmployeeDto,一個(gè)是 EmployeeDto2,即實(shí)現(xiàn)了父類映射到父類,子類映射到子類。
如果去掉 Include 方法,則映射后 dto 中兩個(gè)元素的類型均為 EmployeeDto。
6 方法到屬性映射
AutoMapper 不僅能實(shí)現(xiàn)屬性到屬性映射,還可以實(shí)現(xiàn)方法到屬性的映射,并且不需要任何配置,方法名可以和屬性名一致,也可以帶有 Get
前綴。
例如下例的 Employee.GetFullName()
方法,可以映射到 EmployeeDto.FullName
屬性。
public class Employee { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string GetFullName() { return $"{FirstName} {LastName}"; } } public class EmployeeDto { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string FullName { get; set; } }
7 自定義映射
當(dāng)源類型與目標(biāo)類型名稱不一致時(shí),或者需要對(duì)源數(shù)據(jù)做一些轉(zhuǎn)換時(shí),可以用自定義映射。
public class Employee { public int ID { get; set; } public string Name { get; set; } public DateTime JoinTime { get; set; } } public class EmployeeDto { public int EmployeeID { get; set; } public string EmployeeName { get; set; } public int JoinYear { get; set; } }
如上例,ID
和 EmployeeID
屬性名不同,JoinTime
和 JoinYear
不僅屬性名不同,屬性類型也不同。
var config = new MapperConfiguration(cfg => { cfg.CreateMap<Employee, EmployeeDto>() .ForMember("EmployeeID", opt => opt.MapFrom(src => src.ID)) .ForMember(dest => dest.EmployeeName, opt => opt.MapFrom(src => src.Name)) .ForMember(dest => dest.JoinYear, opt => opt.MapFrom(src => src.JoinTime.Year)); });
8 扁平化映射
對(duì)象-對(duì)象映射的常見用法之一是將復(fù)雜的對(duì)象模型并將其展平為更簡單的模型。
public class Employee { public int ID { get; set; } public string Name { get; set; } public Department Department { get; set; } } public class Department { public int ID { get; set; } public string Name { get; set; } } public class EmployeeDto { public int ID { get; set; } public string Name { get; set; } public int DepartmentID { get; set; } public string DepartmentName { get; set; } }
如果目標(biāo)類型上的屬性,與源類型的屬性、方法都對(duì)應(yīng)不上,則 AutoMapper 會(huì)將目標(biāo)成員名按駝峰法拆解成單個(gè)單詞,再進(jìn)行匹配。例如上例中,EmployeeDto.DepartmentID 就對(duì)應(yīng)到了 Employee.Department.ID。
8.1 IncludeMembers
如果屬性命名不符合上述的規(guī)則,而是像下面這樣:
public class Employee { public int ID { get; set; } public string Name { get; set; } public Department Department { get; set; } } public class Department { public int DepartmentID { get; set; } public string DepartmentName { get; set; } } public class EmployeeDto { public int ID { get; set; } public string Name { get; set; } public int DepartmentID { get; set; } public string DepartmentName { get; set; } }
Department
類中的屬性名,直接跟 EmployeeDto
類中的屬性名一致,則可以使用 IncludeMembers
方法指定。
9 嵌套映射
有時(shí),我們可能不需要展平??慈缦吕樱?/p>
public class Employee { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public Department Department { get; set; } } public class Department { public int ID { get; set; } public string Name { get; set; } public string Heads { get; set; } } public class EmployeeDto { public int ID { get; set; } public string Name { get; set; } public DepartmentDto Department { get; set; } } public class DepartmentDto { public int ID { get; set; } public string Name { get; set; } }
我們要將 Employee
映射到 EmployeeDto
,并且將 Department
映射到 DepartmentDto
。
var config = new MapperConfiguration(cfg => { cfg.CreateMap<Employee, EmployeeDto>(); cfg.CreateMap<Department, DepartmentDto>(); });
以上就是C# AutoMapper 使用方法總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于C# AutoMapper 用法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C# 運(yùn)用params修飾符來實(shí)現(xiàn)變長參數(shù)傳遞的方法
一般來說,參數(shù)個(gè)數(shù)都是固定的,定義為集群類型的參數(shù)可以實(shí)現(xiàn)可變數(shù)目參數(shù)的目的,但是.NET提供了更靈活的機(jī)制來實(shí)現(xiàn)可變數(shù)目參數(shù),這就是使用params修飾符2013-09-09用 C# 編寫一個(gè)停放在任務(wù)欄上的圖標(biāo)程序
用 C# 編寫一個(gè)停放在任務(wù)欄上的圖標(biāo)程序...2007-03-03c# 實(shí)現(xiàn)康威生命游戲(細(xì)胞自動(dòng)機(jī))的示例
這篇文章主要介紹了c# 實(shí)現(xiàn)康威生命游戲(細(xì)胞自動(dòng)機(jī))的示例,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-02-02c# Selenium爬取數(shù)據(jù)時(shí)防止webdriver封爬蟲的方法
這篇文章主要介紹了c# Selenium爬取數(shù)據(jù)時(shí)防止webdriver封爬蟲的方法,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2021-01-01C#實(shí)現(xiàn)將HTML網(wǎng)頁或HTML字符串轉(zhuǎn)換為PDF
將HTML轉(zhuǎn)換為PDF可實(shí)現(xiàn)格式保留、可靠打印、文檔歸檔等多種用途,滿足不同領(lǐng)域和情境下的需求,所以本文就來介紹一下如何使用C#實(shí)現(xiàn)將HTML網(wǎng)頁或HTML字符串轉(zhuǎn)換為PDF,有需要的可以參考下2024-01-01