抖音粉丝群1
『7x24小时有问必答』

AI浪潮下的计算机行业——从业者现状与未来展望
前言
谈到对象映射器,AutoMapper 知名度是非常的高,但很少有人知道 Mapster。而为什么选择 Mapster 呢?
理由一:性能优于 AutoMapper ,相关测试位于https://github.com/MapsterMapper/Mapster上查看。
理由二:多学习一项技能
网上查了一下,关于 Mapster 的资料非常少,所以在这里我们详细写下它的用法,以帮助更多的序员宝快速掌握它的用法。
官方文档:https://github.com/MapsterMapper/Mapster/wiki
安装 Mapster
PM> Install-Package Mapster
 或者 
dotnet add package Mapster
定义实体
目的:使用 Mapster 实现 User 到 UserDto 的映射
public class User

{

public string Name { get; set; }

public int Age { get; set; }

public string Sex { get; set; }

public string like { get; set; }

}

public class UserDto

{

public string name { get; set; }

public int UserAge { get; set; }

public string UserSex { get; set; }

public string like { get; set; }

}

简单使用
/*

* 默认情况下,无需任何配置,Mapster会根据两个实体字段名称相同进行匹配

* 第一次调用时,配置会被缓存,第二次将会从缓存中取,以此提升性能

*/

var user = new User();

var dto = user.Adapt();//映射为新对象

user.Adapt(dto);//在目标对象的基础上进行映射

//注意:Adapt扩展方法使用的配置为 `TypeAdapterConfig.GlobalSettings`

Mapster 配置 (TypeAdapterConfig)
可以直接使用 Mapster 内置的全局静态配置 
TypeAdapterConfig.GlobalSettings
,也可以实例化一个配置 
new TypeAdapterConfig()
推荐使用实例化的方式,对 TypeAdapterConfig 进行映射配置。
注:Mapster 默认匹配规则是相同字段名之间进行映射。
方式一
直接在 TypeAdapterConfig 配置对象的映射关系
var config = new TypeAdapterConfig();

//映射规则

config.ForType()

.Map(dest => dest.UserAge, src => src.Age)

.Map(dest => dest.UserSex, src => src.Sex);

var mapper = new Mapper(config);//务必将mapper设为单实例

var user = new User{Name = "xiaowang",Age = 18,Sex = "boy"};

var dto = mapper.Map(user);

字段带有前后缀,可以使用 
NameMatchingStrategy.ConvertDestinationMemberName
 对目标字段名称进行替换,使得它和源字段名称相同。

还有替换源字段的方法
NameMatchingStrategy.ConvertSourceMemberName
注意:如果一个
ForType
定义多个
NameMatchingStrategy
,后定义的会覆盖先定义的规则,所以只有最后定义的规则会生效
var config = new TypeAdapterConfig();

//使用

config.ForType()

.NameMatchingStrategy(NameMatchingStrategy.ConvertDestinationMemberName(dest => dest.Replace("User", "")));

方式二
使用接口的方式,需要实现 
IRegister
//实现接口 IRegister

public class UserDtoRegister : IRegister

{

public void Register(TypeAdapterConfig config)

{

config.ForType()

Map(dest => dest.UserAge, src => src.Age);

//...

}

}

//实例化Mapper

var config = new TypeAdapterConfig();

//var config = TypeAdapterConfig.GlobalSettings;

//只有要给定 IRegister 所在的程序集名称,Mapster 会自动识别 IRegister,进行配置注入。

config.Scan("程序集名称1","程序集名称2");

var mapper = new Mapper(config);//务必设置为单实例

忽略字段
var config = new TypeAdapterConfig();

//映射规则

config.ForType()

.Map(dest => dest.UserAge, src => src.Age)

.Map(dest => dest.UserSex, src => src.Sex);

.IgnoreNullValues(true)//忽略空值映射

.Ignore(dest => dest.UserAge)//忽略指定字段

.IgnoreAttribute(typeof(DataMemberAttribute))//忽略指定特性的字段

.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase)//忽略字段名称的大小写

.IgnoreNonMapped(true);//忽略除以上配置的所有字段

config.ForType()

.IgnoreMember((member, side) => !member.Type.Namespace.StartsWith("System"));//实现更细致的忽略规则

member
side
分别对应
IMemberModel
MemberSide
,这里我贴出相应的源码。
//包含了映射类型的信息

public interface IMemberModel

{

Type Type { get; }

string Name { get; }

object? Info { get; }

AccessModifier SetterModifier { get; }

AccessModifier AccessModifier { get; }

IEnumerable GetCustomAttributes(bool inherit);

}

//标识当前是源类型还是目标类型

public enum MemberSide

{

Source = 0,

Destination = 1

}

分支(Fork)
Mapster 的 Fork 功能允许我们定义局部的映射规则,并且分支不会重复编译,不需要考虑性能问题。
var config = new TypeAdapterConfig();

var mapper = new Mapper(config);

var user = new User{Name = "xiaowang",Age = 18,Sex = "boy"};

var dto = mapper.From(user).ForkConfig(forked =>

{

//该分支规则,不会重复编译,仅限该语句中有效,不会影响config的配置

forked.ForType().Map(dest => dest.name, src => src.Name);

})

.AdaptToType();//映射为新对象

dto = mapper.From(user).ForkConfig(forked =>

{

forked.ForType().Map(dest => dest.name, src => src.Name);

})

.AdaptTo(new UserDto());//在目标对象基础上进行映射

NewConfig 方法
NewConfig 方法允许我们对两个类型之间新建配置,如果两个类型之前配置了映射关系,则 NewConfig 方法会覆盖之前的配置
var config = new TypeAdapterConfig();

config.ForType().Map(dest => dest.UserAge, src => src.Age);

//...

//覆盖 User 和 UserDto 之前的配置

config.NewConfig().Map(dest=>dest.UserAge,src=>100);

//扩展知识:覆盖Mapster默认静态配置

TypeAdapterConfig.NewConfig().Default.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);

运行时传参
允许运行时传入数据,干预映射过程
var config = new TypeAdapterConfig();

config.ForType()

.Map(dest => dest.name, src => MapContext.Current.Parameters["userName"]);//配置运行时参数

var mapper = new Mapper(config);

//使用时传入数据

var user = new User();

var dto = mapper.From(user).BuildAdapter().AddParameters("userName","xiaowang").AdaptToType();

其他知识点
我们尽量不要把实体间的映射规则配置到 
TypeAdapterConfig.GlobalSettings
 (默认配置)。随着业务的发展,一个配置很难兼顾所有业务,可能会出行冲突的情况,相对复杂的业务,可以新建一个
TypeAdapterConfig
,或者使用 
config.Clone()
能轻松复制一份配置。全局配置可以放一些简单的配置项,例如:映射时忽略大小写。
注意:Adapt 扩展方法使用的是 
TypeAdapterConfig.GlobalSettings
小技巧Adapt 扩展方法的使用
Dictionary<string,object> dict = new User().Adaptstring[ span],object="">>();//object 到 Dictionary 的转换

string s = 123.Adapt<string>(); //equal to 123.ToString();

int i = "123".Adapt<int>(); //equal to int.Parse("123");

拦截映射前后
BeforeMapping
 方法和 
AfterMapping
//BeforeMapping 映射执行前

config.ForType().BeforeMapping((src, dest) =>

{

src.Age = 100;

dest.UserAge = src.Age + 10;

});

//AfterMapping 映射执行后

//...

更多的使用技巧可以查看官方文档:https://github.com/MapsterMapper/Mapster/wiki

string[>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

Copyright 2010-2015. All rights reserved. 

微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码