翼度科技»论坛 编程开发 .net 查看内容

使用Roslyn的源生成器生成DTO

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
前言

源生成器的好处很多, 通过在编译时生成代码,可以减少运行时的反射和动态代码生成,从而提高应用程序的性能, 有时候需要对程序AOT以及裁剪编译的dll也是需要用SG来处理的。
我们开发程序应该都绕不过Mapper对象映射,用的比较多的库可能就是AutoMapper,Maspter之内的三方库吧;这些库很强大但是因为内部实现存在反射,因此开发的程序就没办法AOT了,因此如果程序不是很复杂但是又有很特殊的需求,建议使用SG来实现Mapper
功能演示

这里我演示下自己开发的AutoDto生成DTO功能:
比如我们有一个User的类,需要生成UserDto
  1. public class User
  2. {
  3.         public string Id { get; set; } = null!;
  4.         public string FirstName { get; set; } = null!;
  5.         public string LastName { get; set; } = null!;
  6.         public int? Age { get; set; }
  7.         public string? FullName => $"{FirstName} {LastName}";
  8. }
复制代码
定义UserDto并标注特性:
  1. [AutoDto<User>(nameof(User.Id))]//这里我们假设排除Id属性
  2. public partial record UserDto;
复制代码
就这样,源生成器将自动为我们生成对应的Dto:
  1. partial record class UserDto
  2. {
  3.         /// <inheritdoc cref = "User.FirstName"/>
  4.         public string FirstName { get; set; }
  5.         /// <inheritdoc cref = "User.LastName"/>
  6.         public string LastName { get; set; }
  7.         /// <inheritdoc cref = "User.Age"/>
  8.         public int? Age { get; set; }
  9. }
复制代码
并同时为我们生成一个简单的Mapper扩展方法:
  1. public static partial class UserToUserDtoExtentions
  2. {
  3.         /// <summary>
  4.         /// mapper to UserDto
  5.         /// </summary>
  6.         /// <returns></returns>
  7.         public static UserDto MapperToUserDto(this User model)
  8.         {
  9.                 return new UserDto()
  10.                 {
  11.                         FirstName = model.FirstName,
  12.                         LastName = model.LastName,
  13.                         Age = model.Age,
  14.                         FullName = model.FullName,
  15.                 };
  16.         }
  17. }
复制代码
实现代码

[code]static void GENDTO(Compilation compilation, ImmutableArray nodes, SourceProductionContext context){        if (nodes.Length == 0) return;        StringBuilder envStringBuilder = new();        envStringBuilder.AppendLine("// ");        envStringBuilder.AppendLine("using System;");        envStringBuilder.AppendLine("using System.Collections.Generic;");        envStringBuilder.AppendLine("using System.Text;");        envStringBuilder.AppendLine("using System.Threading.Tasks;");        envStringBuilder.AppendLine("#pragma warning disable");        foreach (var nodeSyntax in nodes.AsEnumerable())        {                //Cast()                //Cast()                if (nodeSyntax is not TypeDeclarationSyntax node)                {                        continue;                }                //如果是Record类                var isRecord = nodeSyntax is RecordDeclarationSyntax;                //如果不含partial关键字,则不生成                if (!node.Modifiers.Any(x => x.IsKind(SyntaxKind.PartialKeyword)))                {                        continue;                }                AttributeSyntax? attributeSyntax = null;                foreach (var attr in node.AttributeLists.AsEnumerable())                {                        var attrName = attr.Attributes.FirstOrDefault()?.Name.ToString();                        if (attrName?.IndexOf(AttributeValueMetadataNameDto, System.StringComparison.Ordinal) == 0)                        {                                attributeSyntax = attr.Attributes.First(x => x.Name.ToString().IndexOf(AttributeValueMetadataNameDto, System.StringComparison.Ordinal) == 0);                                break;                        }                }                if (attributeSyntax == null)                {                        continue;                }                //转译的Entity类名                var entityName = string.Empty;                string pattern = @"(?

举报 回复 使用道具