Automapper
Automapper 顾名思义就是自动完成两个对象之间的copy,一个不错的教程:https://dotnettutorials.net/lesson/automapper-in-c-sharp/
不过这个教程的最后一节涉及到的UseValue 及 ResolveUsing 都已经停用了,目前有其他的方式,详见下面的例子中注释的5. 和 6. 。
1 namespace TestAutoMapper 2 { 3 public class Address 4 { 5 public string City { get; set; } 6 public string State { get; set; } 7 public string Country { get; set; } 8 9 public override string ToString() 10 { 11 return $"\n\tCity: {City}\n\tState: {State}\n\tCountry: {Country}"; 12 } 13 14 } 15 16 public class Department 17 { 18 public string DeptName { get; set; } 19 20 public string DeptCity { get; set; } 21 22 public override string ToString() 23 { 24 return $"\n\tDeptName: {DeptName}\n\tDeptCity: {DeptCity}"; 25 } 26 } 27 28 29 public class Employee 30 { 31 public string Name { get; set; } 32 public int Age { get; set; } 33 public int Salary { get; set; } 34 public Address Address { get; set; } 35 public Department Department { get; set; } 36 public string SchoolName { get; set; } 37 public string SchoolLoc { get; set; } 38 public string Dummy { get; set; } 39 40 41 public override string ToString() 42 { 43 return $"Name: {Name}\nAge: {Age}\nSalary: {Salary}\nAddress: {Address}\nDepartment: {Department}\nSchoolName: {SchoolName}\nSchoolLoc: {SchoolLoc}\nDummy: {Dummy}"; 44 } 45 } 46 }
1 using System; 2 3 namespace TestAutoMapper 4 { 5 public class AddressDTO 6 { 7 public string CityName { get; set; } 8 public string State { get; set; } 9 public string Country { get; set; } 10 11 public override string ToString() 12 { 13 return $"\n\tCityName:{CityName}\n\tState:{State}\n\tCountry:{Country}"; 14 } 15 } 16 17 public class SchoolDTO 18 { 19 public string SchoolName { get; set; } 20 public string SchoolLoc { get; set; } 21 22 public override string ToString() 23 { 24 return $"\n\tSchoolName: {SchoolName}\n\tSchoolLoc: {SchoolLoc}"; 25 } 26 } 27 28 public class EmployeeDTO 29 { 30 public string FullName { get; set; } 31 public int Age { get; set; } 32 public int Salary { get; set; } 33 public AddressDTO AddressDTO { get; set; } 34 public string DeptName { get; set; } 35 public string DeptCity { get; set; } 36 public SchoolDTO SchoolInfo { get; set; } 37 public string Dummy { get; set; } 38 public string FixedItem { get; set; } 39 public DateTime UpdateTime { get; set; } 40 public override string ToString() 41 { 42 return $"FullName: {FullName}\nAge: {Age}\nSalary: {Salary}\nAddressDTO: {AddressDTO}\nDeptName: {DeptName}\nDeptCity: {DeptCity}\nSchoolInfo: {SchoolInfo}\nDummy: {Dummy}\nFixedValue: {FixedItem}\nUpdateTime: {UpdateTime}"; 43 } 44 } 45 }
program.cs
1 using AutoMapper; 2 using System; 3 4 namespace TestAutoMapper 5 { 6 7 class Program 8 { 9 static void Main() 10 { 11 var config = new MapperConfiguration(cfg => 12 { 13 cfg.CreateMap<Address, AddressDTO>() 14 .ForMember(dest => dest.CityName, act => act.MapFrom(src => src.City)); 15 16 cfg.CreateMap<Employee, EmployeeDTO>() 17 .ForMember(dest => dest.Age, act => act.Condition(src => (src.Age > 40))) // 1. condition mapping 18 .ForMember(dest => dest.FullName, act => act.MapFrom(src => src.Name)) // 2. different name 19 .ForMember(dest => dest.DeptName, act => act.MapFrom(src => src.Department.DeptName)) // 3. source itme is complex, target is primary 20 .ForMember(dest => dest.DeptCity, act => act.MapFrom(src => src.Department.DeptCity)) 21 .ForMember(dest => dest.AddressDTO, act => act.MapFrom(src => src.Address)) 22 .ForMember(dest => dest.Dummy, act => act.Ignore()) // 4. Ignore item mapping 23 .ForMember(dest => dest.FixedItem, act => act.MapFrom(src => "Fixed Value")) // 5. set fixed value to target 24 .ForMember(dest => dest.UpdateTime, act => act.MapFrom(src => DateTime.Now )) // 6. set dynamic value to target 25 .ForMember(dest => dest.SchoolInfo, act => act.MapFrom(src => new SchoolDTO() // 7. source item is primary, target is complex 26 { 27 SchoolName = src.SchoolName, 28 SchoolLoc = src.SchoolLoc 29 })); 30 }); 31 32 Address empAddress = new Address 33 { 34 City = "Mumbai", 35 State = "Maharashtra", 36 Country = "India" 37 }; 38 39 Department empDept = new Department 40 { 41 DeptName = "IT", 42 DeptCity = "NewYork" 43 }; 44 45 Employee emp = new Employee 46 { 47 Name = "James", 48 Age = 30, 49 Salary = 20000, 50 Address = empAddress, 51 Department = empDept, 52 SchoolName = "MIT", 53 SchoolLoc = "USA", 54 Dummy = "Dummy item will be ignore" 55 }; 56 57 var mapper = new Mapper(config); 58 var empDTO = mapper.Map<EmployeeDTO>(emp); 59 60 var defaultColor = Console.ForegroundColor; 61 Console.ForegroundColor = ConsoleColor.Red; 62 63 Console.WriteLine("Copy from:"); 64 Console.WriteLine(); 65 Console.WriteLine(emp); 66 Console.WriteLine(); 67 Console.ForegroundColor = ConsoleColor.Green; 68 Console.WriteLine("to"); 69 Console.WriteLine(); 70 Console.WriteLine(empDTO); 71 Console.ForegroundColor = defaultColor; 72 } 73 } 74 }
这个例子也很直观:将一个类Employee 的对象的值复制到另一个类 EmployeeDTO 的对象。这两个类的属性有完全一样的,也有些区别。
复制的过程中会按照如下的规则(除了0之外,其他的都对应例子中的注释):
0. 属性相同的值会被直接复制不需要任何操作
1. 复制的时候可以加上条件,比如Age > 40才复制,否则不复制
2. 属性不一致的情况下需要额外定义,否则不会复制
3. 源数据的属性是一个复杂类型(一个类)Department,而目标是简单类型,需要明确给出对应关系
4. 如果某些属性不想复制,也可以设置为忽略 ignore
5. 给目标属性赋一个固定值
6. 给目标属性赋一个需要运算的值
7. 与 3. 相反,由简单类型复制到复杂类型
上面例子的输出如下:
注:本文中的例子为一个.NET console project, 使用 Nuget 安装一下 AutoMapper 即可。