利用源生成器实现对象映射,在编译阶段生成映射代码,减少运行时反射
利用源生成器,在编译阶段生成映射代码,减少运行时反射
这里有一个MappingTestModel类和MappingTestModelDto类,实现对象自身的拷贝,或者MappingTestModel映射MappingTestModelDto
GenMapperAttribute标注了类型需要生成映射方法,同时实现IAutoMap接口(由生成器实现接口, 类型转换时可以用obj is IAutoMap map检查)
构造函数可选参数为目标类型,默认是自身
MapBetweenAttribute用于自定义转换动作,支持定义在类上或者属性上,两者的有一下区别
- 定义在类上时,必须使用3个参数的构造函数,并且支持单对多,多对单的映射
- 定义在属性上,必须使用2个参数的构造函数,并且只支持单对单映射
[GenMapper(typeof(MappingTestModelDto))]
[MapBetween(typeof(MappingTestModelDto), ["Id", "Name", "Level"], "Label", By = nameof(FormatLabel))]
public partial class MappingTestModel
{
public int Id { get; set; }
[MapBetween(typeof(MappingTestModelDto), nameof(MappingTestModelDto.DisplayName))]
public string Name { get; set; }
public string Level { get; set; }
public DateTime Deadline { get; set; }
[MapBetween(typeof(MappingTestModelDto), nameof(Last),By = nameof(DTL))]
public DateTime Last { get; set; }
private static long DTL(DateTime dt)
{
return dt.Ticks;
}
private static DateTime DTL(long tick)
{
return new DateTime(tick);
}
private static string FormatLabel(int id, string name, string level)
{
return $"{id + 1}-{name}-{level}";
}
//可选反向映射方法
private static (int, string, string) FormatLabel(string label)
{
var values = label.Split('-');
return (int.Parse(values[0]), values[1], values[2]);
}
}
public class MappingTestModelDto
{
public string Id { get; set; }
public string DisplayName { get; set; }
public int Level { get; set; }
public string Deadline { get; set; }
public long Last { get; set; }
public string Label { get; set; }
}
对于MappingTestModel类型,生成器将生成如下代码
using AutoGenMapperGenerator;
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace TestProject1.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "0.0.7.0")]
/// <inheritdoc/>
partial class MappingTestModel : AutoGenMapperGenerator.IAutoMap
{
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "0.0.7.0")]
public TestProject1.Models.MappingTestModelDto MapToMappingTestModelDto()
{
var _result_gen = new TestProject1.Models.MappingTestModelDto();
_result_gen.Label = TestProject1.Models.MappingTestModel.FormatLabel(this.Id, this.Name, this.Level);
_result_gen.Id = this.Id.ToString();
_result_gen.DisplayName = this.Name;
if (int.TryParse(this.Level.ToString(), out var _Level_out_gen))
{
_result_gen.Level = _Level_out_gen;
}
_result_gen.Deadline = this.Deadline.ToString();
_result_gen.Last = TestProject1.Models.MappingTestModel.DTL(this.Last);
return _result_gen;
}
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "0.0.7.0")]
public void MapFromMappingTestModelDto(TestProject1.Models.MappingTestModelDto _target_gen)
{
var _Label_arr_gen = TestProject1.Models.MappingTestModel.FormatLabel(_target_gen.Label);
this.Id = _Label_arr_gen.Item1;
this.Name = _Label_arr_gen.Item2;
this.Level = _Label_arr_gen.Item3;
if (int.TryParse(_target_gen.Id, out var _Id_out_gen))
{
this.Id = _Id_out_gen;
}
this.Name = _target_gen.DisplayName;
this.Level = _target_gen.Level.ToString();
if (System.DateTime.TryParse(_target_gen.Deadline, out var _Deadline_out_gen))
{
this.Deadline = _Deadline_out_gen;
}
this.Last = TestProject1.Models.MappingTestModel.DTL(_target_gen.Last);
}
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "0.0.7.0")]
public object? MapTo(string? target = null)
{
return MapToMappingTestModelDto();
}
[global::System.CodeDom.Compiler.GeneratedCode("AutoGenMapperGenerator.AutoMapperGenerator", "0.0.7.0")]
public void MapFrom(object? value)
{
if (value is TestProject1.Models.MappingTestModelDto source)
{
MapFromMappingTestModelDto(source);
}
}
}
}
因此,对于一个已有的MappingTestModel实例,你可以用如下方法获取MappingTestModelDto实例
var p = new MappingTestModel();
var pdto = p.MapToMappingTestModelDto();
// 或者使用IAutoMap接口
var dto2 = p.MapTo<MappingTestModelDto>(nameof(MappingTestModelDto))
总结
源生成器号称编译阶段的反射,性能上确定很有优势。但是目前配置的话确实不方便,需要在字段上进行Attribute标注,字段匹配规则也还没设置
感兴趣的可以看看源码生成器源码地址

浙公网安备 33010602011771号