MVVM框架下的Mapster工具包

2024-05-09 09:04
文章标签 框架 工具包 mvvm mapster

本文主要是介绍MVVM框架下的Mapster工具包,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

引言

高性能对象映射框架 Mapster

1、简单映射

2、数据类型

2.1、基本类型

2.2、枚举类型

2.3、字符串类型

2.4、集合

2.5、可映射对象

3、映射配置

3.1、全局设置

3.2、基于条件的映射

3.3、未知源类型

3.4、泛型类型

4、映射配置的继承

4.1、源类型映射配置子类默认继承

 4.2、目标类型映射配置默认不继承

4.3、手动继承

5、配置实例

5.1、不同场景独立配置

 5.2、映射配置的复制与扩展

 5.3、配置入口和遗漏补充

6、不同程序集的映射配置

6.1、Scan

6.2、Apply

 7、映射验证和编译

7.1、验证映射配置是否存在错误

7.2、编译配置

8、自定义映射

8.1、自定义属性映射关系

8.2、条件映射

8.3、映射私有成员

8.4、多级映射

8.5、空值

8.6、多个源映射到同一个类型

 8.7、特性

AdaptIgnore 特性


引言

WPF应用程序的三层架构:Model->ViewModel->View。个人理解就是将后台的运行配置文件或则结果Model转换为可以与窗体交互的ViewModel,ViewModel 再与窗体进行深度绑定,实现后台与前端的解耦。ViewModel作为中间介质包含Model的开放属性,同时又有和View交互的衍生属性或则命令Command。Mapster提供了一种Model<->ViewModel的映射方法,通过Adapt扩展方法实现属性相互映射。

高性能对象映射框架 Mapster

Mapster的高性能可由以下对比列表得出:

MethodMeanStdDevErrorGen 0Gen 1Gen 2Allocated
'Mapster 6.0.0'108.59 ms1.198 ms1.811 ms31000.0000--124.36 MB
'Mapster 6.0.0 (Roslyn)'38.45 ms0.494 ms0.830 ms31142.8571--124.36 MB
'Mapster 6.0.0 (FEC)'37.03 ms0.281 ms0.472 ms29642.8571--118.26 MB
'Mapster 6.0.0 (Codegen)'34.16 ms0.209 ms0.316 ms31133.3333--124.36 MB
'ExpressMapper 1.9.1'205.78 ms5.357 ms8.098 ms59000.0000--236.51 MB
'AutoMapper 10.0.0'420.97 ms23.266 ms35.174 ms87000.0000--350.95 MB

对比其他框架占用更少的内存, 拥有更好的性能。

1、简单映射

默认会将两个类型中相同名称的属性进行映射

//映射到新对象
var destObject = sourceObject.Adapt<Destination>();
//映射到现有对象
sourceObject.Adapt(destObject);

扩展方法 Adapt,为避免装箱/拆箱 请使用第一个版本指定类型

var dest = src.Adapt<TSource, TDestination>();
var dest = src.Adapt<TDestination>();

2、数据类型

2.1、基本类型

基本类型的转换 ,例如: int/bool/dobule/decimal ,包括可空的基本类型。

只要C#支持类型转换的类型,那么在 Mapster 中也同样支持转换。

decimal i = 123.Adapt<decimal>(); //equal to (decimal)123

2.2、枚举类型

Mapster 会自动把枚举映射到数字类型,同样也支持 字符串到枚举 和 枚举到字符串的映射。

.NET 默认实现 枚举/字符串 转换非常慢,Mapster 比 .NET 的默认实现快两倍。

在 Mapster 中,字符串转枚举,如果字符串为空或空字符串,那么枚举将初始化为第一个枚举值。

在Mapster中,也支持标记的枚举。

var e = "Read, Write, Delete".Adapt<FileShare>();  
//FileShare.Read | FileShare.Write | FileShare.Delete

对于不同类型的枚举,Mapster 默认将值映射为枚举。调用 EnumMappingStrategy 方法可以指定枚举映射方式,如:

TypeAdapterConfig.GlobalSettings.Default.EnumMappingStrategy(EnumMappingStrategy.ByName);

2.3、字符串类型

在 Mapster 中,将其它类型映射为字符串时,Mapster 将调用类型的 ToString 方法。

如果将字符串映射为类型时,Mapster 将调用类型的 Parse 方法。

var s = 123.Adapt<string>(); // 等同于: 123.ToString();
var i = "123".Adapt<int>();  // 等同于: int.Parse("123");

2.4、集合

包括列表、数组、集合、包括各种接口的字典之间的映射: IList<T>, ICollection<T>, IEnumerable<T>, ISet<T>, IDictionary<TKey, TValue> 等等…

var list = db.Pocos.ToList();
var target = list.Adapt<IEnumerable<Dto>>();  

2.5、可映射对象

Mapster 可以使用以下规则映射两个不同的对象

  • 源类型和目标类型属性名称相同。 例如: dest.Name = src.Name
  • 源类型有 GetXXXX 方法。例如: dest.Name = src.GetName()
  • 源类型属性有子属性,可以将子属性的赋值给符合条件的目标类型属性,例如: dest.ContactName = src.Contact.Namedest.Contact_Name = src.Contact.Name
class Staff {public string Name { get; set; }public int GetAge() { return (DateTime.Now - this.BirthDate).TotalDays / 365.25; }public Staff Supervisor { get; set; }...
}struct StaffDto {public string Name { get; set; }public int Age { get; set; }public string SupervisorName { get; set; }
}var dto = staff.Adapt<StaffDto>();  
//dto.Name = staff.Name, dto.Age = staff.GetAge(), dto.SupervisorName = staff.Supervisor.Name

可映射对象类型包括:

  • 结构体
  • 接口
  • 实现 IDictionary<string, T> 接口的字典类型
  • Record 类型 (类、结构体、接口)

对象转换为字典的例子:

var point = new { X = 2, Y = 3 };
var dict = point.Adapt<Dictionary<string, int>>();
dict["Y"].ShouldBe(3);

Record 类型的例子:

class Person {public string Name { get; }public int Age { get; }public Person(string name, int age) {this.Name = name;this.Age = age;}
}var src = new { Name = "Mapster", Age = 3 };
var target = src.Adapt<Person>();

自动映射 Record 类型有一些限制:

  • Record 类型属性必须没有 set
  • 只有一个非空构造函数
  • 构造函数中的所有参数名称必须与属性名称相同

如果不符合以上规则,需要增加额外的 MapToConstructor 配置

3、映射配置

使用 TypeAdapterConfig<TSource, TDestination>.NewConfig()TypeAdapterConfig<TSource, TDestination>.ForType() 配置类型映射;

当调用 NewConfig 方法时,将会覆盖已存在的类型映射配置。

TypeAdapterConfig<TSource, TDestination>.NewConfig().Ignore(dest => dest.Age).Map(dest => dest.FullName,src => string.Format("{0} {1}", src.FirstName, src.LastName));

如若不想覆盖之前已经创建好的映射配置,可以使用 TypeAdapterConfig<TSource, TDestination>.ForType()

ForType 方法与 NewConfig 的差别:如果指定类型映射配置不存在,那它将创建一个新的映射,如果指定类型的映射配置已存在,那么它将会扩展已有的映射配置,而不是删除或替换已有的映射配置。

TypeAdapterConfig<TSource, TDestination>.ForType().Ignore(dest => dest.Age).Map(dest => dest.FullName,src => string.Format("{0} {1}", src.FirstName, src.LastName));

3.1、全局设置

使用全局设置将映射策略应用到所有的映射配置。

TypeAdapterConfig.GlobalSettings.Default.PreserveReference(true);

对于特定的类型映射,你可以使用 TypeAdapterConfig<SimplePoco, SimpleDto>.NewConfig() 覆盖全局映射配置。

TypeAdapterConfig<SimplePoco, SimpleDto>.NewConfig().PreserveReference(false);

3.2、基于条件的映射

你可以使用 When 方法,当满足某个条件时,进行一些特定的映射操作。

下面的这个例子,当任何一个映射的 源类型和目标类型 相同时,不映射 Id 属性:

TypeAdapterConfig.GlobalSettings.When((srcType, destType, mapType) => srcType == destType).Ignore("Id");

在下面这个例子中,映射配置只对 IQueryable 生效:

TypeAdapterConfig.GlobalSettings.When((srcType, destType, mapType) => mapType == MapType.Projection).IgnoreAttribute(typeof(NotMapAttribute));

3.3、未知源类型

在不确定源类型的时候,使用 ForDestinationType 来创建针对于 目标类型 的映射配置。

比如使用 AfterMapping 在映射完成后调用目标类型对象的 Validate 方法:

TypeAdapterConfig.GlobalSettings.ForDestinationType<IValidator>().AfterMapping(dest => dest.Validate());

注意!在上面的代码段中指定目标类型为 IValidator 接口,那么将会把映射配置应用到所有实现了 IValidator 的类型。

3.4、泛型类型

如果映射的是泛型类型,可以通过将泛型类型传给 ForType 来创建设置.

TypeAdapterConfig.GlobalSettings.ForType(typeof(GenericPoco<>), typeof(GenericDto<>)).Map("value", "Value");

4、映射配置的继承

4.1、源类型映射配置子类默认继承

Mapster 默认会把 源类型的 映射配置 应用到 源类型的子类。

如创建了一个 SimplePoco -> SimpleDto 的映射配置:

TypeAdapterConfig<SimplePoco, SimpleDto>.NewConfig().Map(dest => dest.Name, src => src.Name + "_Suffix");

那么继承了 SimplePocoDerivedPoco 也将应用同样的映射配置:

var dest = TypeAdapter.Adapt<DerivedPoco, SimpleDto>(src); 
//dest.Name = src.Name + "_Suffix"

如果不希望子类使用父类映射配置,可以设置 AllowImplicitSourceInheritancefalse 关闭继承:

TypeAdapterConfig.GlobalSettings.AllowImplicitSourceInheritance = false;

 4.2、目标类型映射配置默认不继承

Mapster 默认不会把 目标类型的 映射配置 应用到 目标类型的子类。

可以设置 AllowImplicitDestinationInheritance 开启:

TypeAdapterConfig.GlobalSettings.AllowImplicitDestinationInheritance = true;

4.3、手动继承

可以通过 Inherits 方法显示的继承类型映射配置:

TypeAdapterConfig<DerivedPoco, DerivedDto>.NewConfig().Inherits<SimplePoco, SimpleDto>();

父类也可继承子类的映射关系

TypeAdapterConfig<Vehicle, VehicleDto>.NewConfig().Include<Car, CarDto>();Vehicle vehicle = new Car { Id = 1, Name = "Car", Make = "Toyota" };
var dto = vehicle.Adapt<Vehicle, VehicleDto>();dto.ShouldBeOfType<CarDto>();
((CarDto)dto).Make.ShouldBe("Toyota"); //The 'Make' property doesn't exist in Vehicle

5、配置实例

5.1、不同场景独立配置

在 Mapster 中,默认的配置实例为 TypeAdapterConfig.GlobalSettings ,如果需要在不同场景下有不同的映射配置,Mapster 提供了 TypeAdapterConfig 用于实现此需求:

var config = new TypeAdapterConfig();
config.Default.Ignore("Id");

如何给 配置实例 添加l类型映射配置?

直接使用 NewConfigForType 方法即可:

config.NewConfig<TSource, TDestination>().Map(dest => dest.FullName,src => string.Format("{0} {1}", src.FirstName, src.LastName));config.ForType<TSource, TDestination>().Map(dest => dest.FullName,src => string.Format("{0} {1}", src.FirstName, src.LastName));

注意! 配置实例 在程序中一定要作为单例存在,否则会影响性能! 

通过将 配置实例 作为参数传给 Adapt 方法来应用特定的类型映射配置:

var result = src.Adapt<TDestination>(config);

也可以创建一个指定 TypeAdapterConfigMapper,使用 Mapper 来做映射:

var mapper = new Mapper(config);
var result = mapper.Map<TDestination>(src);

 5.2、映射配置的复制与扩展

如果想从现有的配置中创建配置实例,可以使用 Clone 方法。

例如 复制全局配置实例 :

var newConfig = TypeAdapterConfig.GlobalSettings.Clone();
var newConfig = oldConfig.Clone();

Fork 方法内部直接调用 Clone 方法,但是使用 Fork 方法的形式与使用 Clone 方法有些许差别。

 Fork 可以内部直接进行映射扩展

var forked = mainConfig.Fork(config => {config.ForType<Poco, Dto>().Map(dest => dest.code, src => src.Id);});var dto = poco.Adapt<Dto>(forked);

以上代码等同于使用 Clone 方法实现的以下代码:

var forked = mainConfig.Clone();
forked.ForType<Poco, Dto>().Map(dest => dest.code, src => src.Id);var dto = poco.Adapt<Dto>(forked);

 5.3、配置入口和遗漏补充

映射配置应该只初始化并且只进行一次配置。因此在编写代码的时候不能将映射配置和映射调用放在同一个地方。多次设置同一个配置会抛出异常,如下:

config.ForType<Poco, Dto>().Ignore("Id");
var dto1 = poco1.Adapt<Dto>(config);config.ForType<Poco, Dto>().Ignore("Id"); //<--- 这里将抛出异常,因为在这之前已经触发过了映射
var dto2 = poco2.Adapt<Dto>(config);

一般会放在程序的入口,如 Main方法 Startup方法

但是难免在使用时会对映射配置进行补充,这时可通过Fork函数进行补充,不用担心性能问题,只有第一次使用配置实例时会编译,之后的调用将从缓存中获取。

var dto = poco.Adapt<Dto>(config.Fork(forked => forked.ForType<Poco, Dto>().Ignore("Id"));

6、不同程序集的映射配置

将映射配置分布在许多不同的程序集上是比较常见的。

6.1、Scan

允许扫描程序集中的这些规则会很有帮助,这样你就有一些基本的方法来组织规则,并且不会忘记调用注册码。在某些情况下,甚至可能需要按特定顺序注册程序集,以便某些规则优先于其他规则。装配扫描有助于实现这一点。

程序集扫描很简单,只需在程序集中创建任意数量的实现,然后从类中调用:IRegisterScanTypeAdapterConfig

public class MyRegister : IRegister
{public void Register(TypeAdapterConfig config){config.NewConfig<TSource, TDestination>();//OR to create or enhance an existing configurationconfig.ForType<TSource, TDestination>();}
}

要在全局级别进行扫描和注册,请执行以下操作:

TypeAdapterConfig.GlobalSettings.Scan(assembly1, assembly2, assemblyN)

对于特定的配置实例:

var config = new TypeAdapterConfig();
config.Scan(assembly1, assembly2, assemblyN);

6.2、Apply

如果使用其他程序集扫描库(如MEF),则可以使用Apply方法轻松应用注册。

var registers = container.GetExports<IRegister>();
config.Apply(registers);

Apply方法还允许您有选择地从一个或多个而不是每个组件中进行拾取。

var register = new MockingRegister();
config.Apply(register);

 7、映射验证和编译

7.1、验证映射配置是否存在错误

调用 TypeAdapterConfig<Source, Destination>.NewConfg()Compile 方法将验证 特定类型的映射配置是否存在错误;

调用 配置实例 的 Compile 方法以验证 配置实例中的映射配置 是否存在错误;

另外,如果启用了 显式映射 , 它还将包含没有在映射器中注册的类的错误。

// 验证特定配置
var config = TypeAdapterConfig<Source, Destination>.NewConfig();
config.Compile();// 验证整个配置实例的配置
TypeAdapterConfig<Source, Destination>.NewConfig();
TypeAdapterConfig<Source2, Destination2>.NewConfig();
TypeAdapterConfig.GlobalSettings.Compile();

7.2、编译配置

Mapster 默认将在第一次调用映射时自动编译:

var result = poco.Adapt<Dto>();

你也可以通过调用 配置实例 或 特定映射配置的Compile 方法编译映射:

// 全局配置实例
TypeAdapterConfig.GlobalSettings.Compile();// 配置实例
var config = new TypeAdapterConfig();
config.Compile();// 特定配置
var config = TypeAdapterConfig<Source, Destination>.NewConfig();
config.Compile();

推荐在程序添加映射配置完成后调用一次 Compile 方法,可以快速验证 映射配置中是否存在错误,而不是在运行到某一行业务代码时触发错误降低效率。

注意!调用 Compile 方法前应该完成所有的映射配置,调用 Compile 方法之后 配置实例 就不允许添加修改其它映射配置!

8、自定义映射

8.1、自定义属性映射关系

TypeAdapterConfig<TSource, TDestination>.NewConfig().Map(dest => dest.FullName,src => string.Format("{0} {1}", src.FirstName, src.LastName));
TypeAdapterConfig<TSource, TDestination>.NewConfig().Map(dest => dest.Gender,      // dest.Gender: Genders.Male 或 Genders.Female 枚举类型src => src.GenderString); // src.GenderString: "Male" 或 "Female" 字符串类型

8.2、条件映射

可以通过设置 Map 方法的第三个参数,实现在 源对象 满足某些条件下进行映射;

当存在多个条件的情况下,Mapster 会依次往下执行判断条件是否满足,直到满足条件为止;

当找不到满足条件的映射时,将分配空值或默认值:

TypeAdapterConfig<TSource, TDestination>.NewConfig().Map(dest => dest.FullName, src => "Sig. " + src.FullName, srcCond => srcCond.Country == "Italy").Map(dest => dest.FullName, src => "Sr. " + src.FullName, srcCond => srcCond.Country == "Spain").Map(dest => dest.FullName, src => "Mr. " + src.FullName);

 使用 IgnoreIf 方法,当满足条件时将忽略此成员的映射:

TypeAdapterConfig<TSource, TDestination>.NewConfig().IgnoreIf((src, dest) => !string.IsNullOrEmpty(dest.Name), dest => dest.Name);

 Mapster 默认映射时会将 源对象的所有成员映射到目标对象,如果不想映射空值,那么可以使用 IgnoreNullValues 方法进行配置:

TypeAdapterConfig<TSource, TDestination>.NewConfig().IgnoreNullValues(true);

 注意!如果想要在满足条件时跳过映射,应该使用 IgnoreIf,详情可参阅

8.3、映射私有成员

TypeAdapterConfig<TSource, TDestination>.NewConfig().Map("PrivateDestName", "PrivateSrcName");

8.4、多级映射

TypeAdapterConfig<Poco, Dto>.NewConfig().Map(dest => dest.Child.Name, src => src.Name);

 映射 Dto 中属性的值到 Poco

public class Poco
{public string Name { get; set; }public string Extra { get; set; }
}public class Dto
{public string Name { get; set; }public SubDto SubDto { get; set; }
}
public class SubDto
{public string Extra { get; set; }
}

如果想将 Dto 中的所有属性和 Dto.SubDto 中的所有属性映射到 Poco,那么可以通过配置 dto.SubDto 映射到 Poco 来实现:

TypeAdapterConfig<Dto, Poco>.NewConfig().Map(poco => poco, dto => dto.SubDto);

8.5、空值

如果 src.Childnull,那么映射到 dest.Name 的配置不会抛出 NullPointerException ,而是映射空值:

TypeAdapterConfig<Poco, Dto>.NewConfig().Map(dest => dest.Name, src => src.Child.Name);

8.6、多个源映射到同一个类型

如果想将 Dto1Dto2两个类型映射到 Poco 类型,那么可以通过将 Dto1 Dto2 包装成一个 tuple,然后将 tuple.Item1tuple.Item2 映射到 Poco 来实现:

TypeAdapterConfig<(Dto1, Dto2), Poco>.NewConfig().Map(dest => dest, src => src.Item1).Map(dest => dest, src => src.Item2);

 8.7、特性

AdaptIgnore 特性

当一个属性有 [AdaptIgnore] 标记时,这个属性将不会被映射:

public class Product {public string Id { get; set; }public string Name { get; set; }[AdaptIgnore]public decimal Price { get; set; }
}

当一个成员有 [AdaptIgnore] 标记时,不管是 源到目标 还是 目标到源 的映射都将会忽略这个成员,可以使用 MemberSide 指定单方的忽略。

例如,只有 Product 当作 源映射时,Price 字段才会被忽略:

public class Product {public string Id { get; set; }public string Name { get; set; }[AdaptIgnore(MemberSide.Source)]public decimal Price { get; set; }
}

AdaptMember 特性标记

使用 [AdaptMember] 特性标记可以实现修改映射的名称。

例如,将 Id 映射为 Code:

public class Product {[AdaptMember("Code")]public string Id { get; set; }public string Name { get; set; }
}

使用 [AdaptMember] 特性标记可以实现映射非公开成员:

public class Product {[AdaptMember]private string HiddenId { get; set; }public string Name { get; set; }
}

这篇关于MVVM框架下的Mapster工具包的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/972976

相关文章

[分布式网络通讯框架]----Zookeeper客户端基本操作----ls、get、create、set、delete

Zookeeper数据结构 zk客户端常用命令 进入客户端 在bin目录下输入./zkCli.sh 查看根目录下数据ls / 注意:要查看哪一个节点,必须把路径写全 查看节点数据信息 get /第一行代码数据,没有的话表示没有数据 创建节点create /sl 20 /sl为节点的路径,20为节点的数据 注意,不能跨越创建,也就是说,创建sl2的时候,必须确保sl

【服务器08】之【游戏框架】之【加载主角】

首先简单了解一下帧率 FixedUpdate( )   >   Update( )   >   LateUpdate( ) 首先FixedUpdate的设置值 默认一秒运行50次 虽然默认是0.02秒,但FiexedUpdate并不是真的0.02秒调用一次,因为在脚本的生命周期内,FixedUpdate有一个小循环,这个循环也是通过物理时间累计看是不是大于0.02了,然后调用一次。有

Java中的集合框架使用技巧

Java中的集合框架使用技巧 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨Java中集合框架的使用技巧,这些技巧能够帮助我们更高效地处理数据和优化程序性能。 Java集合框架概述 Java集合框架提供了一组实现了各种集合接口的类和接口,用于存储和操作数据。它包括列表、集合、队列和映射等数据结构,能够满足不

[分布式网络通讯框架]----ZooKeeper下载以及Linux环境下安装与单机模式部署(附带每一步截图)

首先进入apache官网 点击中间的see all Projects->Project List菜单项进入页面 找到zookeeper,进入 在Zookeeper主页的顶部点击菜单Project->Releases,进入Zookeeper发布版本信息页面,如下图: 找到需要下载的版本 进行下载既可,这里我已经下载过3.4.10,所以以下使用3.4.10进行演示其他的步骤。

C# 日志框架Serilog使用

1、框架和说明        C#日志框架Serilog支持多种场景输出,简单验证了一下,比较方便        包的安装,推荐直接使用“推荐NuGet包管理器”安装Serilog.AspNetCore,常见的组件都已经集成在一个包中,使用比较方便 2、配置文件        Serilog可以由配置文件来定义行为,而且配置文件的修改即时生效。参考配置文件如下: {"Serilog":

Pytest和Unitest框架对比

在学到自动化的时候,很多同学都遇到了Pytest和Unitest框架,有的人是两个都学,但是学的不精只是知道分别怎么用.不了解两个区别是什么.有的是犹豫到底要学习那个框架.其实要做好自动化测试,是有必要了解不同框架之间的差异化的. Pytest 特点: Pytest采用了更简洁、更灵活的语法风格,使用“assert”语句来进行断言,Pytest可以自动发现并执行以“test_”开头的函数

mysql-mmm框架2

简介 MMM(Master-Master replication manager for MySQL)是一套支持双主故障切换和双主日常管理的脚本程序。MMM使用Perl语言开发,主要用来监控和管理MySQL Master-Master(双主)复制,虽然叫做双主复制,但是业务上同一时刻只允许对一个主进行写入,另一台备选主上提供部分读服务,以加速在主主切换时刻备选主的预热,可以说MMM这套脚本程

MySQL-MMM框架

一、环境简述 1、工作逻辑图 2、MySQL-MMM优缺点 优点:高可用性,扩展性好,出现故障自动切换,对于主主同步,在同一时间只提供一台数据库写操作,保证的数据的一致性。 缺点:Monitor节点是单点,可以结合Keepalived实现高可用。 3、MySQL-MMM工作原理 MMM(Master-Master replication managerfor Mys

基于LangChain框架搭建知识库

基于LangChain框架搭建知识库 说明流程1.数据加载2.数据清洗3.数据切分4.获取向量5.向量库保存到本地6.向量搜索7.汇总调用 说明 本文使用openai提供的embedding模型作为框架基础模型,知识库的搭建目的就是为了让大模型减少幻觉出现,实现起来也很简单,假如你要做一个大模型的客服问答系统,那么就把历史客服问答数据整理好,先做数据处理,在做数据向量化,最后保

简单 使用 的makefile编写 框架

1、指定编译器,如海思平台:CROSS_COMPILE=arm-hisiv100nptl-linux-; 2、指定编译工具:GCC=$(CROSS_COMPILE)gcc   CC=$(CROSS_COMPILE)g++; 3、使用 export 导出 子makefile 要用的变量; 4、定义变量的形式  指定 工程源文件 需要使用到的 “宏”,在后面的 LDFLAGS 里面使用 -D将其