、获取Mapper实例
1. 获取Mapper默认实例
Default是一个静态延迟初始化的默认实例
IMapper mapper = PocoEmit.Mapper.Default;
2. 构造Mapper新实例
除了测试,不建议每次转化调用Create
Create的实例建议定义为静态字段或属性
或者注入IOC容器内重复使用
IMapper mapper = PocoEmit.Mapper.Create();
二、简单类型转化无需配置
什么样的类型转化对PocoEmit来说是简单的呢
1. 基础类型、枚举互转
基础类型、枚举互转无需配置
int intValue = PocoEmit.Mapper.Default.Convert("123");
long longValue = PocoEmit.Mapper.Default.Convert(123);
strting stringValue = PocoEmit.Mapper.Default.Convert(123);
public enum MyColor
{
None = 0,
Red = 1,
Green = 2,
Blue = 3,
}
ConsoleColor color = ConsoleColor.DarkBlue;
// Red
MyColor redColor = PocoEmit.Mapper.Default.Convert(ConsoleColor.Red);
string colorName = PocoEmit.Mapper.Default.Convert(ConsoleColor.Red);
// 1
long colorValue = PocoEmit.Mapper.Default.Convert(MyColor.Red);
/ None
MyColor noneColor = PocoEmit.Mapper.Default.Convert(ConsoleColor.DarkBlue);
2. 可空类型转化
可空类型转化无需配置
int intValue = PocoEmit.Mapper.Default.Convert("123");
long? longValue = PocoEmit.Mapper.Default.Convert(123);
strting stringValue = PocoEmit.Mapper.Default.Convert(123);
User user = PocoEmit.Mapper.Default.Convert(null);
3. 构造函数和属性互转
构造函数和属性互转无需配置
class MyId(int id)
{
public int Id { get; } = id;
}
class MyId2(int? id)
{
public int? Id { get; } = id;
}
3.1 构造函数转化
var myId = PocoEmit.Mapper.Default.Convert(1);
var myId2 = PocoEmit.Mapper.Default.Convert(2);
var myId3 = PocoEmit.Mapper.Default.Convert(3);
var myId4 = PocoEmit.Mapper.Default.Convert(4);
3.2 属性转化
var id = PocoEmit.Mapper.Default.Convert(new MyId(1));
var id2 = PocoEmit.Mapper.Default.Convert(new MyId2(2));
var id3 = PocoEmit.Mapper.Default.Convert(new MyId(3));
var id4 = PocoEmit.Mapper.Default.Convert(new MyId2(4));
4. 复合类型同名属性互转
复合类型同名属性互转无需配置
var dto = PocoEmit.Mapper.Default.Convert(new User { Id = 1, Name = "Jxj1" });
var user = PocoEmit.Mapper.Default.Convert(new UserDTO { Id = 2, Name = "Jxj2" });
var user3 = PocoEmit.Mapper.Default.Convert(new UserDTO { Id = "3", Name = "张三" });
三、一键开启集合类型转化配置
通过UseCollection扩展方法给PocoEmit.Mapper增加集合功能
扩展后PocoEmit.Mapper支持集合(含数组、列表及字典)的转化和复制
支持实体类型包含集合成员的转化和复制
1. 启用集合配置
1.2 开启全局集合配置
对所有Mapper启用集合
应在使用所有Mapper实例之前配置,对已经完成初始化的Mapper实例无效
CollectionContainer.GlobalUseCollection();
1.1 对单个Mapper启用集合
PocoEmit.Mapper.UseCollection();
2.启用集合后集合互转无需配置
User[] source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];
UserDTO[] result = PocoEmit.Mapper.Default.Convert(source);
IEnumerable source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];
UserDTO[] result = PocoEmit.Mapper.Default.Convert, UserDTO[]>(source);
User[] source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];
IEnumerable result = PocoEmit.Mapper.Default.Convert>(source);
Dictionary source = new() { { 1, new User { Id = 1, Name = "Jxj" } } };
UserDTO[] result = PocoEmit.Mapper.Default.Convert, UserDTO[]>(source);
Dictionary source = new() { { 1, new User { Id = 1, Name = "Jxj" } } };
Dictionary result = PocoEmit.Mapper.Default.Convert, Dictionary>(source);
3.启用集合后集合成员互转无需配置
var source = new UserArray { Name = "VIP", Users = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }] };
UserDTOArray result = PocoEmit.Mapper.Default.Convert(source);
四、自定义配置
1. Mapper全局配置
全局配置对所有Mapper适用
全局配置应在使用所有Mapper实例之前配置,对已经完成初始化的Mapper实例无效
1.1 全局配置映射规则
PocoEmit.Mapper.GlobalConfigure(mapper => {
mapper.ConfigureMap()
.Source
.Ignore(nameof(User.Name));
});
1.2 全局配置内部缓存字典大小
配置适当大小可以减少内存占用和扩容
PocoEmit.Mapper.GlobalOptions(options => {
// 转化器数量
options.ConverterCapacity = 100;
});
2. 配置单个Mapper
PocoEmit.Mapper.Default.ConfigureMap()
.Source
.Ignore(nameof(User.Name));
3. 哪些需要配置
3.1 属性名前、后缀
AddPrefix设置前缀
AddSuffix设置后缀
ClearPrefix清空前缀
public class UserCustomDTO(string userName)
{
public int? UId { get; set; }
public string UName { get; } = userName;
}
3.1.1 源类型设置前缀
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Source
.AddPrefix("U");
var source = new UserCustomDTO("Jxj2") { UId = 222 };
var converter = mapper.GetConverter();
User result = converter.Convert(source);
3.1.2 目标类型设置前缀
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Dest
.AddPrefix("U");
var source = new User { Id = 222, Name = "Jxj2" };
var result = mapper.Convert(source);
3.1.3 默认前缀
ConfigureMap会默认把源类型名作为目标类型前缀
ConfigureMap会默认把目标类型名作为源类型前缀
如果默认前缀干扰到正常匹配,可以调用ClearPrefix清空前缀
public class AutoUserDTO
{
public string UserId { get; set; }
public string UserName { get; set; }
}
IMapper mapper = Mapper.Create();
mapper.ConfigureMap();
var source = new AutoUserDTO{ UserId = "222", UserName = "Jxj" };
var converter = mapper.GetConverter();
User result = converter.Convert(source);
3.2 属性一对一配置
3.2.1 通过Source配置
直接MapTo或ForMember
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Source
.MapTo(nameof(User.Id), nameof(UserCustomDTO.UId))
.MapTo(nameof(User.Name), nameof(UserCustomDTO.UName));
var source = new User { Id = 222, Name = "Jxj2" };
var converter = mapper.GetConverter();
UserCustomDTO result = converter.Convert(source);
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Source
.ForMember(nameof(User.Id)).MapTo(nameof(UserCustomDTO.UId))
.ForMember(nameof(User.Name)).MapTo(nameof(UserCustomDTO.UName));
var source = new User { Id = 222, Name = "Jxj2" };
var converter = mapper.GetConverter();
UserCustomDTO result = converter.Convert(source);
3.2.2 通过Dest配置
直接MapFrom或ForMember
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Dest
.MapFrom(nameof(User.Id), nameof(UserCustomDTO.UId))
.MapFrom(nameof(User.Name), nameof(UserCustomDTO.UName));
var source = new UserCustomDTO("Jxj2") { UId = 222 };
var converter = mapper.GetConverter();
User result = converter.Convert(source);
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Dest
.ForMember(nameof(User.Id)).MapFrom(nameof(UserCustomDTO.UId))
.ForMember(nameof(User.Name)).MapFrom(nameof(UserCustomDTO.UName));
var source = new UserCustomDTO("Jxj2") { UId = 222 };
var converter = mapper.GetConverter();
User result = converter.Convert(source);
3.3 忽略成员
3.3.1 被忽略的源类型成员不参与映射
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Source
.Ignore(nameof(User.Name));
var source = new User { Id = 111, Name = "Jxj" };
var converter = mapper.GetConverter();
// result.Name == null
UserDTO result = converter.Convert(source);
3.3.2 被忽略的目标类型成员不会被匹配
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.Dest
.Ignore(nameof(UserDTO.Name));
var source = new User { Id = 111, Name = "Jxj" };
var converter = mapper.GetConverter();
// result.Name == null
UserDTO result = converter.Convert(source);
3.4 指定转化函数
通过UseConvertFunc指定函数直接转化
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.UseConvertFunc(source => new User { Id= source.Id, Name = source.Name });
var source = new UserDTO { Id = 111, Name = "Jxj" };
var converter = mapper.GetConverter();
var result = converter.Convert(source);
3.5 指定构造函数
通过UseActivator指定构造函数
执行完构造函数还会尝试匹配与UseConvertFunc是不同的
IMapper mapper = Mapper.Create();
mapper.ConfigureMap()
.UseActivator(u => new UserCustomDTO(u.Name) { UId = u.Id })
.Source
.MapTo(nameof(User.Id), nameof(UserCustomDTO.UId));
var source = new User { Id = userId, Name = "Jxj2" };
var converter = mapper.GetConverter();
var result = converter.Convert(source);
3.6 指定默认值
3.6.1 指定固定默认值
IMapper mapper = Mapper.Create()
.UseDefault(Repository);
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserDomain user = mapper.Convert(dto);
class UserDomain(UserRepository repository, int id, string name)
{
private readonly UserRepository _repository = repository;
public UserRepository Repository
=> _repository;
public int Id { get; } = id;
public string Name { get; } = name;
// ...
}
static readonly UserRepository Repository = new();
class UserRepository
{
void Add(UserDomain user) { }
void Update(UserDomain entity) { }
void Remove(UserDomain entity) { }
}
注: 如果不指定UserRepository的默认值,以上转化会报异常
注: 以上例子示例给领域模型注入仓储
3.6.2 默认值指定工厂方法
IMapper mapper = Mapper.Create()
.UseDefault(() => MessageId.NewId());
var dto = new MessageDto { Message = "Hello UseDefault" };
MessageDomain message = mapper.Convert(dto);
class MessageDto
{
public string Message { get; set; }
}
class MessageDomain(MessageId id, string message)
{
public MessageId Id { get; } = id;
public string Message { get; } = message;
// ...
}
class MessageId(int id)
{
private static int seed = 1;
public int Id { get; } = id;
public static MessageId NewId()
=> new(seed++);
}
注: 以上例子示例给领域模型注入自增Id
注: 实际项目这里建议调用雪花Id
3.7 转化后补刀
使用UseCheckAction配置转化检查逻辑用来补刀
对于实在不方便配置映射规则的遗留属性进行补刀
static void ConvertAddressCity(Customer customer, CustomerDTO dto)
{
dto.AddressCity = customer.Address.City;
}
var mapper = PocoEmit.Mapper.Default;
mapper.ConfigureMap()
.UseCheckAction(ConvertAddressCity);
CustomerDTO result = mapper.Convert(source);
五、PocoEmit的“继承”和“多态”
1. PocoEmit的“继承”
通过全局配置实现类似继承的效果
前面已经介绍了PocoEmit的全局配置
2. PocoEmit的“多态”
对某些Mapper对象覆盖配置实现与其他Mapper不同的效果
可以用不同的serviceKey注入容器,使用的时候就可以做到无感
2.1 举个发布平台需要“多态”的例子
需要发布时间字段,平台内时间格式很好统一
如果需要接入第三方数据,特别是国外的数据,格式很可能不一样
牺牲性能用复杂逻辑去兼容也不是不可以
这里建议提供多个Mapper的方案,不同渠道用不同的Mapper,每个Mapper只有极少的配置不同
这就是PocoEmit“多态”的应用
2.2 再举个VIP的例子更明显
VIP客户提出各种格式化无关痛痒的问题
一般就写if特殊处理了
这类情况也适用PocoEmit“多态”
六、PocoEmit配合容器使用
1、容器注册转化器
1.1 默认注册
通过容器中默认的IMapper对象或Mapper.Global构造转化器
services.UseConverter();
1.2 指定IPoco对象注册
services.UseConverter(PocoEmit.Mapper.Global);
注: PocoEmit.Mapper.Global继承IPoco接口
1.3 隔离注册
指定IPoco和serviceKey注册
IPoco poco = specialMapper;
services.UseConverter(poco, "special");
1.4 通过IPocoConverter注入
通过构造函数参数、属性等方式注入
public sealed class Mapper(IPocoConverter converter)
: Mapper>
{
// ...
}
2、容器注册复制器
2.1 默认注册
通过容器中默认的IMapper对象或Mapper.Global构造复制器
services.UseCopier();
2.2 指定IMapper对象注册
services.UseCopier(PocoEmit.Mapper.Global);
注: PocoEmit.Mapper.Global继承IMapper接口
2.3 隔离注册
指定IPoco和serviceKey注册

被折叠的 条评论
为什么被折叠?



