利用源生成器,在編譯階段生成對映程式碼,減少執行時反射
這裡有一個Product類和ProductDto類,實現物件自身的複製,或者Product對映ProductDto
GenMapperAttribute
標註了型別需要生成對映方法,同時要求實現IAutoMap
介面(由生成器自動實現)
建構函式可選引數為目標型別,預設是自身
MaoToAttribute
和MapFromAttribute
用於自定義轉換動作,顧名思義,MapTo是用於當前型別轉換到目標型別用的,MapFrom是在目標型別標註的,由當前型別呼叫
public interface IAutoMap
{
object MapTo(string? target = null);
}
[GenMapper]
[GenMapper(typeof(ProductDto))]
internal partial class Product : IAutoMap
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Category { get; set; }
[MapTo(Target = typeof(ProductDto), Name = nameof(ProductDto.Date))]
public DateTime? ProductDate { get; set; }
public IEnumerable<Product> Products { get; set; } = [];
}
internal class ProductDto
{
public static string NameMapFrom(Product p)
{
return $"{p.Category}-{p.Name}";
}
public int Id { get; set; }
[MapFrom(Source = typeof(Product), By = nameof(NameMapFrom))]
public string? Name { get; set; }
//[MapFrom(Source = typeof(Product), Name = nameof(Product.ProductDate))]
public DateTime? Date { get; set; }
}
對於Product型別,生成器將生成如下程式碼
// <auto-generated/>
#pragma warning disable
namespace TestProject1.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "1.0.0.0")]
/// <inheritdoc/>
partial class Product
{
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "1.0.0.0")]
public TestProject1.Models.Product MapToProduct()
{
var result = new TestProject1.Models.Product();
result.Id = this.Id;
result.Name = this.Name;
result.Category = this.Category;
result.ProductDate = this.ProductDate;
result.Products = this.Products;
return result;
}
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "1.0.0.0")]
public TestProject1.Models.ProductDto MapToProductDto()
{
var result = new TestProject1.Models.ProductDto();
result.Date = this.ProductDate;
result.Id = this.Id;
result.Name = TestProject1.Models.ProductDto.NameMapFrom(this);
return result;
}
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "1.0.0.0")]
public object? MapTo(string? target = null)
{
if (string.IsNullOrEmpty(target))
throw new ArgumentNullException(nameof(target), "存在多個目標型別,請指定目標型別,推薦使用nameof(TargetType)");
if (target == nameof(Product))
return MapToProduct();
if (target == nameof(ProductDto))
return MapToProductDto();
throw new ArgumentException("未找到指定目標型別的對映方法");
}
}
}
因此,對於一個已有的Product例項,你可以用如下方法獲取Product新例項和ProductDto例項
var p = new Product();
var p1 = p.MapToProduct();
var pdto = p.MapToProductDto();
// 或者使用IAutoMap介面
var p2 = p.MapTo<Product>(nameof(Product));
var dto2 = p.MapTo<ProductDto>(nameof(ProductDto))
總結
源生成器號稱編譯階段的反射,效能上確定很有優勢。但是目前配置的話確實不方便,需要在欄位上進行Attribute標註,欄位匹配規則也還沒設定
感興趣的可以看看原始碼生成器原始碼地址