首页 > 编程语言 >Mapster (C# 对象映射器)

Mapster (C# 对象映射器)

时间:2024-04-07 23:35:11浏览次数:13  
标签:映射 映射器 C# Age new var Mapster config TypeAdapterConfig

参考:https://www.cnblogs.com/qiqigou/p/13696669.html
官方文档:https://github.com/MapsterMapper/Mapster/wiki

前言

谈到对象映射器,AutoMapper 知名度是非常的高,但很少有人知道 Mapster。性能优于 AutoMapper

安装 Mapster

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<UserDto>();//映射为新对象
user.Adapt(dto);//在目标对象的基础上进行映射

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

Mapster 配置 (TypeAdapterConfig)

默认情况下,无需任何配置,Mapster会根据两个实体字段名称相同进行匹配。
如果需要更复杂的对象映射就需要通过TypeAdapterConfig配置

            TypeAdapterConfig.GlobalSettings.ForType<User, UserDto>()
            //.Ignore(dest => dest.Age);//排除Age属性映射
            //.IgnoreMember((memberModel, memberSide) => memberModel.Name == "Name")//排除Name属性映射,相比Ignore()可以实现更细致的忽略规则
            //.IgnoreIf((src, desc) => src.Age == 18, desc => desc.Age)//如果年龄等于18岁就排除Age属性映射
            //.IgnoreIf((src, desc) => src.Age == 18, "Name", "Age");//如果年龄等于18岁就排除Name、Age属性映射
            //.IgnoreNullValues(true);//如果是属性是空值就排除属性映射
            //.IgnoreAttribute(typeof(ExcludeAttribute));//排除标记了ExcludeAttribute的属性映射
            // .Map(desc => desc.Age, source => source.Age + 10);//指定属性映射规则
            //.IgnoreNonMapped(true);//只映射Map指定的属性,其他属性都排除
            //.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);//忽略字段名称的大小写

            //映射执行前执行
            TypeAdapterConfig.GlobalSettings.ForType<User, UserDto>().BeforeMapping((source, desc) =>
            {
                desc.age = source.Age;
            });
            //映射执行后执行
            TypeAdapterConfig.GlobalSettings.ForType<User, UserDto>().AfterMapping((source, desc) =>
            {
                desc.age = source.Age;
                //desc.Users = source.Adapt<UserDto>();
            });

IMemberModel、MemberSide

//包含了映射类型的信息
public interface IMemberModel
{
    Type Type { get; }
    string Name { get; }
    object? Info { get; }
    AccessModifier SetterModifier { get; }
    AccessModifier AccessModifier { get; }

    IEnumerable<object> GetCustomAttributes(bool inherit);
}
//标识当前是源类型还是目标类型
public enum MemberSide
{
    Source = 0,
    Destination = 1
}

几种配置方式

两种配置方式:全局配置TypeAdapterConfig.GlobalSettings、实例化一个配置new TypeAdapterConfig()
我们尽量不要把实体间的映射规则配置到 TypeAdapterConfig.GlobalSettings (默认配置)。随着业务的发展,一个配置很难兼顾所有业务,可能会出现冲突的情况,相对复杂的业务,可以新建一个TypeAdapterConfig,或者使用 config.Clone()能轻松复制一份配置。全局配置可以放一些简单的配置项,例如:映射时忽略大小写。

注意:Adapt 扩展方法使用的是 TypeAdapterConfig.GlobalSettings

方式一:全局配置

全局静态配置是Mapster内置的

TypeAdapterConfig.GlobalSettings.ForType<User, UserDto>();

方式二:实例化配置

var config = new TypeAdapterConfig();
//映射规则
config.ForType<User, UserDto>()
    .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<UserDto>(user);

方式三: IRegister接口

//实现接口 IRegister
public class UserDtoRegister : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<User,UserDto>()
            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);//务必设置为单实例

方式四:依赖注入

安装包:
PM> Install-Package Mapster.DependencyInjection
startup中注册TypeAdapterConfigServiceMapper

public void ConfigureServices(IServiceCollection services)
{
    ...
    var config = new TypeAdapterConfig();
    // Or
    // var config = TypeAdapterConfig.GlobalSettings;
    services.AddSingleton(config);
    services.AddScoped<IMapper, ServiceMapper>();
}

注册服务后,可以使用IMapper映射对象

public class FooService {
    private readonly IMapper _mapper;
    public FooService(IMapper mapper) {
        _mapper = mapper;
    }
    public void DoSomething(Poco poco) {
        var dto = _mapper.Map<Dto>(poco);
    }
}

注意:ServiceMapper的生命周期取决于你想要注入的服务。它可以是单例的,如果你只注入单例服务。如果任何注入的服务都是瞬态的,那么它也可以是瞬态的。

分支(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<User, UserDto>().Map(dest => dest.name, src => src.Name);
    })
    .AdaptToType<UserDto>();//映射为新对象

dto = mapper.From(user).ForkConfig(forked =>
    {
        forked.ForType<User, UserDto>().Map(dest => dest.name, src => src.Name);
    })
    .AdaptTo(new UserDto());//在目标对象基础上进行映射

NewConfig 方法

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

var config = new TypeAdapterConfig();
config.ForType<User,UserDto>().Map(dest => dest.UserAge, src => src.Age);
//...

//覆盖 User 和 UserDto 之前的配置
config.NewConfig<User,UserDto>().Map(dest=>dest.UserAge,src=>100);

//扩展知识:覆盖Mapster默认静态配置
TypeAdapterConfig<User,UserDto>.NewConfig().Default.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);

小技巧

运行时传参

允许运行时传入数据,干预映射过程

var config = new TypeAdapterConfig();
config.ForType<User, UserDto>()
    .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<UserDto>();

List转换

List<User> userList = new List<User> { user, new User { Name = "fan1", Age = 19 } };
var userDtoList = userList.Adapt<List<UserDto>>();

对象转字典

Dictionary<string,object> dict = new User().Adapt<Dictionary<string,object>>();//object 到 Dictionary 的转换
string s = 123.Adapt<string>(); //equal to 123.ToString();
int i = "123".Adapt<int>();  //equal to int.Parse("123");

映射到现有对象

创建对象后,Mapster会映射到该对象。

sourceObject.Adapt(destObject);

和 EFCore 配合

Mapster 还提供了 ProjectToType Linq 拓展方法减少我们手动 Select 操作,如:
正常的操作:

var destinations = context.Sources
        .Select(p => new Destination {
            Id = p.Id,
            Name = p.Name,
            Surname = p.Surname,
            ....
        })
        .ToList();

使用 Mapster 之后:

var destinations = context.Sources.ProjectToType<Destination>().ToList();

标签:映射,映射器,C#,Age,new,var,Mapster,config,TypeAdapterConfig
From: https://www.cnblogs.com/Alex80/p/18120166

相关文章

  • WPF instantiate class instance as resource
    //xaml<Windowx:Class="WpfApp42.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mic......
  • MacOS虚拟机
    MacOS12虚拟机安装教程目录MacOS12虚拟机安装教程前置条件VMwareworkstation安装步骤!!!完成安装后先不要打开软件!!!解锁vmvare中macos安装功能处理VMware进程和服务解锁MacOS安装功能创建虚拟机安装MacOS12安装VMwareTools工具优化虚拟机mac系统结束语前置条件VMwareWork......
  • c++primer 9.52答案
    萌新业余时间学c++中,学过一点c之前,下面一个自己写的9.52答案,尽量用到了前面学到的知识,与大加分享交流一下,希望能互相讨论学习。/*******************************************************************************************@FilePath:MyDate.h*@Author:YMM*@Date......
  • C++之静态变量和全局变量的区别
    全局变量和静态变量的存储方式是一样的,只是作用域不同。静态局部变量具有局部作用域只对定义自己的函数可见,只被初始化一次,自从初始化一次之后直到程序运行期间一直都在。静态全局变量具有全局作用域作用于定义它的程序文件但是不能作用于项目里的其它文件,这一点和全局变......
  • 每天五分钟掌握深度学习框架pytorch:本专栏说明
    专栏大纲专栏计划更新章节在100章左右,之后还会不断更新,都会配备代码实现。以下是专栏大纲部分代码实现代码获取为了方便用户浏览代码,本专栏将代码同步更新到github中,所有用户可以读完专栏内容和代码解析之后,下载对应的代码,跑一跑模型算法,这样会加深自己对算法模型......
  • Const关键字介绍
    Const关键字用于**声明一个常量或限制变量的修改**,确保其值不被改变。具体来看:1.**定义常量**:使用const关键字可以将变量定义为常量,这意味着一旦赋值后,其值就不允许再被修改。2.**修饰类成员函数**:在C++中,const可以用于修饰类的成员函数,表明该函数不会修改类的任何成员变量......
  • C++学习笔记九--模版
    目录前言1.函数模版1.函数模版的概念和定义2.函数模版的实例化2.类模版1.类模版的概念和定义2.类模版的实例化3.示例代码前言        这篇文章介绍下C++中的模版,包括函数模版和类模版。1.函数模版    在编程的过程中,编写函数都会考虑将其写......
  • Ascend C编程模型与范式
    并行计算架构抽象指令流、信号流、数据流的基本概念指令流:指令流是指在计算过程中,指令的执行顺序。在并行计算架构中,如何安排指令流以最大化并行度和资源利用率是一个关键的设计问题。信号流:信号流涉及到的是在硬件电路中,信号(数据、控制信号等)如何在不同的组件和模块之间......
  • 第四个OpenGL程序,vector 向量 (矩阵变换之 旋转,缩放)后续 绘制多个 图形
    效果: 代码main.cpp#include<iostream>#include<glad/glad.h>#include<glfw3.h>#include"Shader.h"#defineSTB_IMAGE_IMPLEMENTATION#include<stb_image.h>#include<glm/glm.hpp>#include<glm/gtc/matrix_transfo......
  • 论文阅读《Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image De
    BeyondaGaussianDenoiser:ResidualLearningofDeepCNNforImageDenoising发表于IEEETRANSACTIONSONIMAGEPROCESSING,VOL.26,NO.7,JULY2017Paper和CodeAbstract:提出前馈去噪卷积神经网络(DnCNNs),将超深层次结构、学习算法和正则化方法的进展纳入图像去噪......