龙车收 发表于 2024-11-8 18:11:57

使用Roslyn的源生成器生成DTO

前言

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

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

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 = @"(?
页: [1]
查看完整版本: 使用Roslyn的源生成器生成DTO