Skip to content

代码生成 API 高级指南

⏱️ 20-30 分钟 | 📚 高级 | 前置知识: 代码生成基础, 代码生成中级

🎯 学习目标

完成本指南后,你将能够:

  • [ ] 使用 SyntaxFactory 生成复杂的代码结构
  • [ ] 实现高级构建器模式和代码转换技术
  • [ ] 掌握性能优化策略
  • [ ] 处理边缘情况和特殊场景
  • [ ] 实现代码重构和转换工具

📖 核心概念

复杂代码生成的挑战

在高级场景中,代码生成面临以下挑战:

  1. 结构复杂性 - 需要生成嵌套的、相互关联的代码结构
  2. 性能要求 - 大规模代码生成需要优化性能
  3. 可维护性 - 生成的代码需要易于理解和维护
  4. 类型安全 - 确保生成的代码在编译时类型安全

高级技术概览

  • 语法树转换 - 修改现有代码而不是从头生成
  • 模板引擎集成 - 结合模板引擎提高灵活性
  • 增量生成 - 只生成变化的部分
  • 代码分析驱动 - 基于语义分析生成代码

🔧 复杂结构生成

生成泛型类和约束

csharp
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;

/// <summary>
/// 生成复杂的泛型类
/// </summary>
public class AdvancedGenericClassGeneration
{
    /// <summary>
    /// 生成带多个约束的泛型类
    /// public class Repository<TEntity, TKey> 
    ///     where TEntity : class, IEntity<TKey>, new()
    ///     where TKey : struct
    /// </summary>
    public ClassDeclarationSyntax GenerateRepositoryClass()
    {
        return ClassDeclaration("Repository")
            .AddModifiers(Token(SyntaxKind.PublicKeyword))
            .AddTypeParameterListParameters(
                TypeParameter("TEntity"),
                TypeParameter("TKey"))
            .AddConstraintClauses(
                // where TEntity : class, IEntity<TKey>, new()
                TypeParameterConstraintClause("TEntity")
                .AddConstraints(
                    ClassOrStructConstraint(SyntaxKind.ClassConstraint),
                    TypeConstraint(
                        GenericName("IEntity")
                        .AddTypeArgumentListArguments(IdentifierName("TKey"))),
                    ConstructorConstraint()),
                // where TKey : struct
                TypeParameterConstraintClause("TKey")
                .AddConstraints(
                    ClassOrStructConstraint(SyntaxKind.StructConstraint)));
    }
}

生成嵌套类和内部类型

csharp
/// <summary>
/// 生成嵌套类结构
/// </summary>
public class NestedClassGeneration
{
    /// <summary>
    /// 生成包含嵌套类的外部类
    /// public class Outer
    /// {
    ///     public class Inner
    ///     {
    ///         public string Value { get; set; }
    ///     }
    /// }
    /// </summary>
    public ClassDeclarationSyntax GenerateNestedClass()
    {
        // 创建内部类
        var innerClass = ClassDeclaration("Inner")
            .AddModifiers(Token(SyntaxKind.PublicKeyword))
            .AddMembers(
                PropertyDeclaration(
                    PredefinedType(Token(SyntaxKind.StringKeyword)),
                    "Value")
                .AddModifiers(Token(SyntaxKind.PublicKeyword))
                .AddAccessorListAccessors(
                    AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                        .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
                    AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
                        .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))));
        
        // 创建外部类并添加内部类
        return ClassDeclaration("Outer")
            .AddModifiers(Token(SyntaxKind.PublicKeyword))
            .AddMembers(innerClass);
    }
}

生成复杂的方法体

csharp
/// <summary>
/// 生成包含复杂逻辑的方法
/// </summary>
public class ComplexMethodGeneration
{
    /// <summary>
    /// 生成包含 try-catch、循环和条件的方法
    /// public async Task<List<T>> ProcessItemsAsync<T>(IEnumerable<T> items)
    /// {
    ///     var results = new List<T>();
    ///     try
    ///     {
    ///         foreach (var item in items)
    ///         {
    ///             if (item != null)
    ///             {
    ///                 await ProcessAsync(item);
    ///                 results.Add(item);
    ///             }
    ///         }
    ///     }
    ///     catch (Exception ex)
    ///     {
    ///         Logger.LogError(ex);
    ///         throw;
    ///     }
    ///     return results;
    /// }
    /// </summary>
    public MethodDeclarationSyntax GenerateComplexMethod()
    {
        // 创建方法签名
        var method = MethodDeclaration(
            GenericName("Task")
            .AddTypeArgumentListArguments(
                GenericName("List")
                .AddTypeArgumentListArguments(IdentifierName("T"))),
            "ProcessItemsAsync")
        .AddModifiers(
            Token(SyntaxKind.PublicKeyword),
            Token(SyntaxKind.AsyncKeyword))
        .AddTypeParameterListParameters(TypeParameter("T"))
        .AddParameterListParameters(
            Parameter(Identifier("items"))
            .WithType(
                GenericName("IEnumerable")
                .AddTypeArgumentListArguments(IdentifierName("T"))));
        
        // 创建方法体
        var methodBody = Block(
            // var results = new List<T>();
            LocalDeclarationStatement(
                VariableDeclaration(IdentifierName("var"))
                .AddVariables(
                    VariableDeclarator("results")
                    .WithInitializer(
                        EqualsValueClause(
                            ObjectCreationExpression(
                                GenericName("List")
                                .AddTypeArgumentListArguments(IdentifierName("T")))
                            .WithArgumentList(ArgumentList()))))),
            
            // try-catch 块
            TryStatement(
                Block(
                    // foreach (var item in items)
                    ForEachStatement(
                        IdentifierName("var"),
                        "item",
                        IdentifierName("items"),
                        Block(
                            // if (item != null)
                            IfStatement(
                                BinaryExpression(
                                    SyntaxKind.NotEqualsExpression,
                                    IdentifierName("item"),
                                    LiteralExpression(SyntaxKind.NullLiteralExpression)),
                                Block(
                                    // await ProcessAsync(item);
                                    ExpressionStatement(
                                        AwaitExpression(
                                            InvocationExpression(
                                                IdentifierName("ProcessAsync"))
                                            .AddArgumentListArguments(
                                                Argument(IdentifierName("item"))))),
                                    // results.Add(item);
                                    ExpressionStatement(
                                        InvocationExpression(
                                            MemberAccessExpression(
                                                SyntaxKind.SimpleMemberAccessExpression,
                                                IdentifierName("results"),
                                                IdentifierName("Add")))
                                        .AddArgumentListArguments(
                                            Argument(IdentifierName("item"))))))))),
                // catch (Exception ex)
                SingletonList(
                    CatchClause()
                    .WithDeclaration(
                        CatchDeclaration(IdentifierName("Exception"))
                        .WithIdentifier(Identifier("ex")))
                    .WithBlock(
                        Block(
                            // Logger.LogError(ex);
                            ExpressionStatement(
                                InvocationExpression(
                                    MemberAccessExpression(
                                        SyntaxKind.SimpleMemberAccessExpression,
                                        IdentifierName("Logger"),
                                        IdentifierName("LogError")))
                                .AddArgumentListArguments(
                                    Argument(IdentifierName("ex")))),
                            // throw;
                            ThrowStatement()))),
                null,
                null),
            
            // return results;
            ReturnStatement(IdentifierName("results")));
        
        return method.WithBody(methodBody);
    }
}

🏗️ 高级构建器模式

流式构建器实现

csharp
/// <summary>
/// 高级流式构建器,支持链式调用和条件构建
/// </summary>
public class FluentClassBuilder
{
    private string _className;
    private List<SyntaxToken> _modifiers = new();
    private List<MemberDeclarationSyntax> _members = new();
    private List<TypeParameterSyntax> _typeParameters = new();
    private List<TypeParameterConstraintClauseSyntax> _constraints = new();
    private List<BaseTypeSyntax> _baseTypes = new();
    private List<AttributeListSyntax> _attributes = new();
    
    public FluentClassBuilder(string className)
    {
        _className = className;
    }
    
    /// <summary>
    /// 添加修饰符
    /// </summary>
    public FluentClassBuilder WithModifier(SyntaxKind modifier)
    {
        _modifiers.Add(Token(modifier));
        return this;
    }
    
    /// <summary>
    /// 添加泛型参数
    /// </summary>
    public FluentClassBuilder WithTypeParameter(
        string name, 
        params TypeParameterConstraintSyntax[] constraints)
    {
        _typeParameters.Add(TypeParameter(name));
        
        if (constraints.Any())
        {
            _constraints.Add(
                TypeParameterConstraintClause(name)
                .AddConstraints(constraints));
        }
        
        return this;
    }
    
    /// <summary>
    /// 添加基类或接口
    /// </summary>
    public FluentClassBuilder WithBaseType(string typeName)
    {
        _baseTypes.Add(SimpleBaseType(IdentifierName(typeName)));
        return this;
    }
    
    /// <summary>
    /// 添加特性
    /// </summary>
    public FluentClassBuilder WithAttribute(string attributeName, params string[] arguments)
    {
        var attribute = Attribute(IdentifierName(attributeName));
        
        if (arguments.Any())
        {
            attribute = attribute.AddArgumentListArguments(
                arguments.Select(arg =>
                    AttributeArgument(
                        LiteralExpression(
                            SyntaxKind.StringLiteralExpression,
                            Literal(arg))))
                .ToArray());
        }
        
        _attributes.Add(AttributeList(SingletonSeparatedList(attribute)));
        return this;
    }
    
    /// <summary>
    /// 添加成员
    /// </summary>
    public FluentClassBuilder WithMember(MemberDeclarationSyntax member)
    {
        _members.Add(member);
        return this;
    }
    
    /// <summary>
    /// 条件添加成员
    /// </summary>
    public FluentClassBuilder WithMemberIf(
        bool condition, 
        Func<MemberDeclarationSyntax> memberFactory)
    {
        if (condition)
        {
            _members.Add(memberFactory());
        }
        return this;
    }
    
    /// <summary>
    /// 批量添加成员
    /// </summary>
    public FluentClassBuilder WithMembers(IEnumerable<MemberDeclarationSyntax> members)
    {
        _members.AddRange(members);
        return this;
    }
    
    /// <summary>
    /// 构建类声明
    /// </summary>
    public ClassDeclarationSyntax Build()
    {
        var classDecl = ClassDeclaration(_className);
        
        // 添加特性
        if (_attributes.Any())
        {
            classDecl = classDecl.AddAttributeLists(_attributes.ToArray());
        }
        
        // 添加修饰符
        if (_modifiers.Any())
        {
            classDecl = classDecl.AddModifiers(_modifiers.ToArray());
        }
        
        // 添加泛型参数
        if (_typeParameters.Any())
        {
            classDecl = classDecl.WithTypeParameterList(
                TypeParameterList(SeparatedList(_typeParameters)));
        }
        
        // 添加基类和接口
        if (_baseTypes.Any())
        {
            classDecl = classDecl.WithBaseList(
                BaseList(SeparatedList(_baseTypes)));
        }
        
        // 添加约束
        if (_constraints.Any())
        {
            classDecl = classDecl.AddConstraintClauses(_constraints.ToArray());
        }
        
        // 添加成员
        if (_members.Any())
        {
            classDecl = classDecl.AddMembers(_members.ToArray());
        }
        
        return classDecl;
    }
}

使用示例

csharp
/// <summary>
/// 使用流式构建器的示例
/// </summary>
public class FluentBuilderUsageExample
{
    public ClassDeclarationSyntax GenerateRepositoryClass()
    {
        return new FluentClassBuilder("Repository")
            .WithModifier(SyntaxKind.PublicKeyword)
            .WithTypeParameter("TEntity", 
                ClassOrStructConstraint(SyntaxKind.ClassConstraint))
            .WithBaseType("IRepository<TEntity>")
            .WithAttribute("GeneratedCode", "MyGenerator", "1.0")
            .WithMember(CreateSaveMethod())
            .WithMember(CreateLoadMethod())
            .WithMemberIf(includeDeleteMethod, () => CreateDeleteMethod())
            .Build();
    }
    
    private bool includeDeleteMethod = true;
    
    private MethodDeclarationSyntax CreateSaveMethod() { /* ... */ return null; }
    private MethodDeclarationSyntax CreateLoadMethod() { /* ... */ return null; }
    private MethodDeclarationSyntax CreateDeleteMethod() { /* ... */ return null; }
}

🔄 代码转换技术

语法树重写器

csharp
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

/// <summary>
/// 自定义语法重写器,用于转换现有代码
/// </summary>
public class PropertyToFieldRewriter : CSharpSyntaxRewriter
{
    /// <summary>
    /// 将自动属性转换为字段
    /// </summary>
    public override SyntaxNode VisitPropertyDeclaration(
        PropertyDeclarationSyntax node)
    {
        // 只处理自动属性
        if (!IsAutoProperty(node))
        {
            return base.VisitPropertyDeclaration(node);
        }
        
        // 创建字段名 (Name -> _name)
        var fieldName = $"_{char.ToLower(node.Identifier.Text[0])}" +
                       node.Identifier.Text.Substring(1);
        
        // 创建字段声明
        var field = FieldDeclaration(
            VariableDeclaration(node.Type)
            .AddVariables(VariableDeclarator(fieldName)))
        .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword)));
        
        // 保留原属性的前导和尾随 trivia
        field = field.WithLeadingTrivia(node.GetLeadingTrivia())
                    .WithTrailingTrivia(node.GetTrailingTrivia());
        
        return field;
    }
    
    private bool IsAutoProperty(PropertyDeclarationSyntax property)
    {
        return property.AccessorList?.Accessors
            .All(a => a.Body == null && a.ExpressionBody == null) ?? false;
    }
}

使用语法重写器

csharp
/// <summary>
/// 使用语法重写器转换代码
/// </summary>
public class CodeTransformationExample
{
    public string TransformPropertiesToFields(string sourceCode)
    {
        // 解析源代码
        var tree = CSharpSyntaxTree.ParseText(sourceCode);
        var root = tree.GetRoot();
        
        // 应用重写器
        var rewriter = new PropertyToFieldRewriter();
        var newRoot = rewriter.Visit(root);
        
        // 格式化并返回
        return newRoot.NormalizeWhitespace().ToFullString();
    }
}

批量代码转换

csharp
/// <summary>
/// 批量转换多个文件
/// </summary>
public class BatchCodeTransformer
{
    /// <summary>
    /// 转换项目中的所有文件
    /// </summary>
    public async Task TransformProjectAsync(
        string projectPath,
        CSharpSyntaxRewriter rewriter)
    {
        var workspace = MSBuildWorkspace.Create();
        var project = await workspace.OpenProjectAsync(projectPath);
        
        foreach (var document in project.Documents)
        {
            var tree = await document.GetSyntaxTreeAsync();
            var root = await tree.GetRootAsync();
            
            // 应用转换
            var newRoot = rewriter.Visit(root);
            
            // 如果有变化,更新文档
            if (newRoot != root)
            {
                var newDocument = document.WithSyntaxRoot(newRoot);
                // 保存更改...
            }
        }
    }
}

⚡ 性能优化策略

1. 对象池和缓存

csharp
/// <summary>
/// 使用对象池优化性能
/// </summary>
public class SyntaxNodePool
{
    // 缓存常用的 token
    private static readonly SyntaxToken PublicKeyword = 
        Token(SyntaxKind.PublicKeyword);
    private static readonly SyntaxToken PrivateKeyword = 
        Token(SyntaxKind.PrivateKeyword);
    private static readonly SyntaxToken StaticKeyword = 
        Token(SyntaxKind.StaticKeyword);
    private static readonly SyntaxToken SemicolonToken = 
        Token(SyntaxKind.SemicolonToken);
    
    // 缓存常用的类型
    private static readonly Dictionary<string, TypeSyntax> TypeCache = new()
    {
        ["string"] = PredefinedType(Token(SyntaxKind.StringKeyword)),
        ["int"] = PredefinedType(Token(SyntaxKind.IntKeyword)),
        ["bool"] = PredefinedType(Token(SyntaxKind.BoolKeyword)),
        ["void"] = PredefinedType(Token(SyntaxKind.VoidKeyword)),
        ["object"] = PredefinedType(Token(SyntaxKind.ObjectKeyword))
    };
    
    // 缓存常用的访问器
    private static readonly AccessorDeclarationSyntax GetAccessor = 
        AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
            .WithSemicolonToken(SemicolonToken);
    private static readonly AccessorDeclarationSyntax SetAccessor = 
        AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
            .WithSemicolonToken(SemicolonToken);
    
    /// <summary>
    /// 获取缓存的类型
    /// </summary>
    public static TypeSyntax GetType(string typeName)
    {
        if (TypeCache.TryGetValue(typeName, out var type))
        {
            return type;
        }
        
        // 如果不在缓存中,创建并缓存
        type = ParseTypeName(typeName);
        TypeCache[typeName] = type;
        return type;
    }
    
    /// <summary>
    /// 创建属性(使用缓存的节点)
    /// </summary>
    public static PropertyDeclarationSyntax CreateProperty(
        string typeName,
        string propertyName)
    {
        return PropertyDeclaration(GetType(typeName), propertyName)
            .AddModifiers(PublicKeyword)
            .AddAccessorListAccessors(GetAccessor, SetAccessor);
    }
}

2. 批量操作优化

csharp
/// <summary>
/// 批量操作优化示例
/// </summary>
public class BatchOperationOptimization
{
    /// <summary>
    /// ✅ 好的做法:批量添加成员
    /// </summary>
    public ClassDeclarationSyntax CreateClassOptimized(
        string className,
        List<PropertyInfo> properties)
    {
        // 一次性创建所有属性
        var members = properties
            .Select(p => SyntaxNodePool.CreateProperty(p.Type, p.Name))
            .ToArray();
        
        // 一次性添加所有成员
        return ClassDeclaration(className)
            .AddModifiers(Token(SyntaxKind.PublicKeyword))
            .AddMembers(members);
    }
    
    /// <summary>
    /// ❌ 不好的做法:逐个添加成员
    /// </summary>
    public ClassDeclarationSyntax CreateClassSlow(
        string className,
        List<PropertyInfo> properties)
    {
        var classDecl = ClassDeclaration(className)
            .AddModifiers(Token(SyntaxKind.PublicKeyword));
        
        // 每次调用 AddMembers 都会创建新对象
        foreach (var prop in properties)
        {
            var property = SyntaxNodePool.CreateProperty(prop.Type, prop.Name);
            classDecl = classDecl.AddMembers(property);
        }
        
        return classDecl;
    }
    
    public class PropertyInfo
    {
        public string Type { get; set; }
        public string Name { get; set; }
    }
}

3. 延迟格式化

csharp
/// <summary>
/// 延迟格式化优化
/// </summary>
public class LazyFormattingOptimization
{
    /// <summary>
    /// ✅ 好的做法:最后才格式化
    /// </summary>
    public string GenerateMultipleClassesOptimized(List<string> classNames)
    {
        // 创建所有类(不格式化)
        var classes = classNames
            .Select(name => ClassDeclaration(name)
                .AddModifiers(Token(SyntaxKind.PublicKeyword)))
            .ToArray();
        
        // 创建命名空间
        var namespaceDecl = NamespaceDeclaration(ParseName("MyNamespace"))
            .AddMembers(classes);
        
        // 创建编译单元
        var compilationUnit = CompilationUnit()
            .AddMembers(namespaceDecl);
        
        // 只在最后格式化一次
        return compilationUnit.NormalizeWhitespace().ToFullString();
    }
    
    /// <summary>
    /// ❌ 不好的做法:每次都格式化
    /// </summary>
    public string GenerateMultipleClassesSlow(List<string> classNames)
    {
        var sb = new StringBuilder();
        
        foreach (var name in classNames)
        {
            var classDecl = ClassDeclaration(name)
                .AddModifiers(Token(SyntaxKind.PublicKeyword))
                .NormalizeWhitespace();  // 每次都格式化
            
            sb.AppendLine(classDecl.ToFullString());
        }
        
        return sb.ToString();
    }
}

4. 并行生成

csharp
/// <summary>
/// 并行代码生成
/// </summary>
public class ParallelCodeGeneration
{
    /// <summary>
    /// 并行生成多个类
    /// </summary>
    public CompilationUnitSyntax GenerateClassesInParallel(
        List<ClassDefinition> definitions)
    {
        // 并行生成所有类
        var classes = definitions
            .AsParallel()
            .Select(def => GenerateClass(def))
            .ToArray();
        
        // 组装成编译单元
        return CompilationUnit()
            .AddMembers(
                NamespaceDeclaration(ParseName("Generated"))
                .AddMembers(classes))
            .NormalizeWhitespace();
    }
    
    private ClassDeclarationSyntax GenerateClass(ClassDefinition definition)
    {
        // 生成单个类的逻辑
        return ClassDeclaration(definition.Name)
            .AddModifiers(Token(SyntaxKind.PublicKeyword));
    }
    
    public class ClassDefinition
    {
        public string Name { get; set; }
    }
}

5. 内存优化

csharp
/// <summary>
/// 内存优化技巧
/// </summary>
public class MemoryOptimization
{
    /// <summary>
    /// 使用 Span<T> 和 stackalloc 减少堆分配
    /// </summary>
    public string GenerateCodeWithSpan(ReadOnlySpan<char> className)
    {
        // 使用 stackalloc 在栈上分配小数组
        Span<char> buffer = stackalloc char[256];
        
        // 处理类名...
        
        return ClassDeclaration(className.ToString())
            .AddModifiers(Token(SyntaxKind.PublicKeyword))
            .NormalizeWhitespace()
            .ToFullString();
    }
    
    /// <summary>
    /// 使用 StringBuilder 池
    /// </summary>
    private static readonly ObjectPool<StringBuilder> StringBuilderPool = 
        new DefaultObjectPool<StringBuilder>(
            new StringBuilderPooledObjectPolicy());
    
    public string GenerateCodeWithPooledStringBuilder()
    {
        var sb = StringBuilderPool.Get();
        try
        {
            // 使用 StringBuilder...
            sb.AppendLine("public class MyClass");
            sb.AppendLine("{");
            sb.AppendLine("}");
            
            return sb.ToString();
        }
        finally
        {
            StringBuilderPool.Return(sb);
        }
    }
}

🎨 高级代码模式

访问者模式实现

csharp
/// <summary>
/// 使用访问者模式遍历和修改语法树
/// </summary>
public class SyntaxVisitorExample : CSharpSyntaxWalker
{
    private readonly List<string> _classNames = new();
    
    /// <summary>
    /// 访问类声明
    /// </summary>
    public override void VisitClassDeclaration(ClassDeclarationSyntax node)
    {
        _classNames.Add(node.Identifier.Text);
        
        // 继续访问子节点
        base.VisitClassDeclaration(node);
    }
    
    /// <summary>
    /// 获取所有类名
    /// </summary>
    public IReadOnlyList<string> GetClassNames(SyntaxNode root)
    {
        _classNames.Clear();
        Visit(root);
        return _classNames;
    }
}

策略模式用于代码生成

csharp
/// <summary>
/// 代码生成策略接口
/// </summary>
public interface ICodeGenerationStrategy
{
    MemberDeclarationSyntax Generate(PropertyInfo property);
}

/// <summary>
/// 自动属性生成策略
/// </summary>
public class AutoPropertyStrategy : ICodeGenerationStrategy
{
    public MemberDeclarationSyntax Generate(PropertyInfo property)
    {
        return PropertyDeclaration(
            ParseTypeName(property.Type),
            property.Name)
        .AddModifiers(Token(SyntaxKind.PublicKeyword))
        .AddAccessorListAccessors(
            AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
            AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
                .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
    }
}

/// <summary>
/// 字段支持的属性生成策略
/// </summary>
public class BackingFieldPropertyStrategy : ICodeGenerationStrategy
{
    public MemberDeclarationSyntax Generate(PropertyInfo property)
    {
        // 生成带后备字段的属性
        // 实现略...
        return null;
    }
}

/// <summary>
/// 使用策略模式的代码生成器
/// </summary>
public class StrategyBasedGenerator
{
    private readonly ICodeGenerationStrategy _strategy;
    
    public StrategyBasedGenerator(ICodeGenerationStrategy strategy)
    {
        _strategy = strategy;
    }
    
    public ClassDeclarationSyntax GenerateClass(
        string className,
        List<PropertyInfo> properties)
    {
        var members = properties
            .Select(p => _strategy.Generate(p))
            .ToArray();
        
        return ClassDeclaration(className)
            .AddModifiers(Token(SyntaxKind.PublicKeyword))
            .AddMembers(members);
    }
}

public class PropertyInfo
{
    public string Type { get; set; }
    public string Name { get; set; }
}

🔍 边缘情况处理

处理特殊字符和标识符

csharp
/// <summary>
/// 处理特殊字符和保留字
/// </summary>
public class SpecialCharacterHandling
{
    /// <summary>
    /// 转义保留字
    /// </summary>
    public string EscapeReservedKeyword(string identifier)
    {
        var keywords = new HashSet<string>
        {
            "class", "public", "private", "int", "string", "void",
            "if", "else", "for", "while", "return", "new"
        };
        
        return keywords.Contains(identifier) ? $"@{identifier}" : identifier;
    }
    
    /// <summary>
    /// 创建安全的标识符
    /// </summary>
    public IdentifierNameSyntax CreateSafeIdentifier(string name)
    {
        var safeName = EscapeReservedKeyword(name);
        return IdentifierName(safeName);
    }
    
    /// <summary>
    /// 处理包含特殊字符的字符串
    /// </summary>
    public LiteralExpressionSyntax CreateStringLiteral(string value)
    {
        // Roslyn 会自动处理转义
        return LiteralExpression(
            SyntaxKind.StringLiteralExpression,
            Literal(value));
    }
    
    /// <summary>
    /// 创建 verbatim 字符串
    /// </summary>
    public LiteralExpressionSyntax CreateVerbatimString(string value)
    {
        return LiteralExpression(
            SyntaxKind.StringLiteralExpression,
            Literal(value, value));  // 第二个参数是原始值
    }
}

处理 Nullable 引用类型

csharp
/// <summary>
/// 处理 C# 8.0+ 的 nullable 引用类型
/// </summary>
public class NullableReferenceTypeHandling
{
    /// <summary>
    /// 创建 nullable 引用类型属性
    /// public string? Name { get; set; }
    /// </summary>
    public PropertyDeclarationSyntax CreateNullableProperty(
        string typeName,
        string propertyName,
        bool isNullable)
    {
        TypeSyntax type = ParseTypeName(typeName);
        
        // 如果是引用类型且可空,添加 ? 标记
        if (isNullable && IsReferenceType(typeName))
        {
            type = NullableType(type);
        }
        
        return PropertyDeclaration(type, propertyName)
            .AddModifiers(Token(SyntaxKind.PublicKeyword))
            .AddAccessorListAccessors(
                AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
                    .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
                AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
                    .WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
    }
    
    private bool IsReferenceType(string typeName)
    {
        var valueTypes = new HashSet<string>
        {
            "int", "long", "short", "byte", "sbyte",
            "uint", "ulong", "ushort",
            "float", "double", "decimal",
            "bool", "char",
            "DateTime", "DateTimeOffset", "TimeSpan", "Guid"
        };
        
        return !valueTypes.Contains(typeName);
    }
}

处理泛型类型参数

csharp
/// <summary>
/// 处理复杂的泛型类型
/// </summary>
public class GenericTypeHandling
{
    /// <summary>
    /// 解析泛型类型字符串
    /// 例如: "List<Dictionary<string, int>>"
    /// </summary>
    public TypeSyntax ParseGenericType(string typeString)
    {
        // 简单实现:使用 ParseTypeName
        return ParseTypeName(typeString);
    }
    
    /// <summary>
    /// 创建嵌套泛型类型
    /// Dictionary<string, List<int>>
    /// </summary>
    public TypeSyntax CreateNestedGenericType()
    {
        return GenericName("Dictionary")
            .AddTypeArgumentListArguments(
                PredefinedType(Token(SyntaxKind.StringKeyword)),
                GenericName("List")
                .AddTypeArgumentListArguments(
                    PredefinedType(Token(SyntaxKind.IntKeyword))));
    }
    
    /// <summary>
    /// 创建带约束的泛型方法
    /// public T Create<T>() where T : new()
    /// </summary>
    public MethodDeclarationSyntax CreateGenericMethodWithConstraint()
    {
        return MethodDeclaration(
            IdentifierName("T"),
            "Create")
        .AddModifiers(Token(SyntaxKind.PublicKeyword))
        .AddTypeParameterListParameters(TypeParameter("T"))
        .AddConstraintClauses(
            TypeParameterConstraintClause("T")
            .AddConstraints(ConstructorConstraint()))
        .WithBody(Block(
            ReturnStatement(
                ObjectCreationExpression(IdentifierName("T"))
                .WithArgumentList(ArgumentList()))));
    }
}

🧪 测试和验证

单元测试代码生成

csharp
using Xunit;

/// <summary>
/// 代码生成单元测试
/// </summary>
public class CodeGenerationTests
{
    [Fact]
    public void GenerateClass_WithProperties_ShouldCreateValidCode()
    {
        // Arrange
        var generator = new FluentClassBuilder("Person");
        
        // Act
        var classDecl = generator
            .WithModifier(SyntaxKind.PublicKeyword)
            .WithMember(SyntaxNodePool.CreateProperty("string", "Name"))
            .WithMember(SyntaxNodePool.CreateProperty("int", "Age"))
            .Build();
        
        var code = classDecl.NormalizeWhitespace().ToFullString();
        
        // Assert
        Assert.Contains("public class Person", code);
        Assert.Contains("public string Name { get; set; }", code);
        Assert.Contains("public int Age { get; set; }", code);
    }
    
    [Fact]
    public void GenerateGenericClass_WithConstraints_ShouldBeValid()
    {
        // Arrange & Act
        var classDecl = new AdvancedGenericClassGeneration()
            .GenerateRepositoryClass();
        
        var code = classDecl.NormalizeWhitespace().ToFullString();
        
        // Assert
        Assert.Contains("public class Repository<TEntity, TKey>", code);
        Assert.Contains("where TEntity : class", code);
        Assert.Contains("where TKey : struct", code);
    }
    
    [Theory]
    [InlineData("class", "@class")]
    [InlineData("public", "@public")]
    [InlineData("myVar", "myVar")]
    public void EscapeReservedKeyword_ShouldHandleCorrectly(
        string input,
        string expected)
    {
        // Arrange
        var handler = new SpecialCharacterHandling();
        
        // Act
        var result = handler.EscapeReservedKeyword(input);
        
        // Assert
        Assert.Equal(expected, result);
    }
}

集成测试

csharp
/// <summary>
/// 集成测试:验证生成的代码可以编译
/// </summary>
public class CodeCompilationTests
{
    [Fact]
    public void GeneratedCode_ShouldCompile()
    {
        // Arrange
        var generator = new FluentClassBuilder("TestClass");
        var classDecl = generator
            .WithModifier(SyntaxKind.PublicKeyword)
            .WithMember(SyntaxNodePool.CreateProperty("string", "Name"))
            .Build();
        
        var compilationUnit = CompilationUnit()
            .AddUsings(UsingDirective(ParseName("System")))
            .AddMembers(
                NamespaceDeclaration(ParseName("TestNamespace"))
                .AddMembers(classDecl))
            .NormalizeWhitespace();
        
        var code = compilationUnit.ToFullString();
        
        // Act
        var syntaxTree = CSharpSyntaxTree.ParseText(code);
        var compilation = CSharpCompilation.Create(
            "TestAssembly",
            new[] { syntaxTree },
            new[]
            {
                MetadataReference.CreateFromFile(typeof(object).Assembly.Location)
            },
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
        
        var diagnostics = compilation.GetDiagnostics();
        
        // Assert
        var errors = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error);
        Assert.Empty(errors);
    }
}

性能基准测试

csharp
using BenchmarkDotNet.Attributes;

/// <summary>
/// 性能基准测试
/// </summary>
[MemoryDiagnoser]
public class CodeGenerationBenchmarks
{
    private List<PropertyInfo> _properties;
    
    [GlobalSetup]
    public void Setup()
    {
        _properties = Enumerable.Range(0, 100)
            .Select(i => new PropertyInfo
            {
                Type = "string",
                Name = $"Property{i}"
            })
            .ToList();
    }
    
    [Benchmark]
    public ClassDeclarationSyntax GenerateClass_Optimized()
    {
        return new BatchOperationOptimization()
            .CreateClassOptimized("TestClass", _properties);
    }
    
    [Benchmark]
    public ClassDeclarationSyntax GenerateClass_Slow()
    {
        return new BatchOperationOptimization()
            .CreateClassSlow("TestClass", _properties);
    }
    
    public class PropertyInfo
    {
        public string Type { get; set; }
        public string Name { get; set; }
    }
}

💡 实战案例

案例 1: 自动生成 DTO 映射代码

csharp
/// <summary>
/// 自动生成 DTO 到实体的映射代码
/// </summary>
public class DtoMappingGenerator
{
    /// <summary>
    /// 生成映射方法
    /// public static Entity ToEntity(this EntityDto dto)
    /// {
    ///     return new Entity
    ///     {
    ///         Id = dto.Id,
    ///         Name = dto.Name,
    ///         // ...
    ///     };
    /// }
    /// </summary>
    public MethodDeclarationSyntax GenerateMappingMethod(
        string dtoTypeName,
        string entityTypeName,
        List<string> propertyNames)
    {
        // 创建对象初始化器
        var initializers = propertyNames.Select(propName =>
            AssignmentExpression(
                SyntaxKind.SimpleAssignmentExpression,
                IdentifierName(propName),
                MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    IdentifierName("dto"),
                    IdentifierName(propName))));
        
        return MethodDeclaration(
            IdentifierName(entityTypeName),
            "ToEntity")
        .AddModifiers(
            Token(SyntaxKind.PublicKeyword),
            Token(SyntaxKind.StaticKeyword))
        .AddParameterListParameters(
            Parameter(Identifier("dto"))
            .WithType(IdentifierName(dtoTypeName))
            .WithModifiers(TokenList(Token(SyntaxKind.ThisKeyword))))
        .WithBody(Block(
            ReturnStatement(
                ObjectCreationExpression(IdentifierName(entityTypeName))
                .WithInitializer(
                    InitializerExpression(
                        SyntaxKind.ObjectInitializerExpression,
                        SeparatedList<ExpressionSyntax>(initializers))))));
    }
}

案例 2: 生成验证代码

csharp
/// <summary>
/// 自动生成数据验证代码
/// </summary>
public class ValidationCodeGenerator
{
    /// <summary>
    /// 生成验证方法
    /// public bool Validate(out List<string> errors)
    /// {
    ///     errors = new List<string>();
    ///     
    ///     if (string.IsNullOrEmpty(Name))
    ///         errors.Add("Name is required");
    ///     
    ///     if (Age < 0)
    ///         errors.Add("Age must be positive");
    ///     
    ///     return errors.Count == 0;
    /// }
    /// </summary>
    public MethodDeclarationSyntax GenerateValidationMethod(
        List<ValidationRule> rules)
    {
        var statements = new List<StatementSyntax>();
        
        // errors = new List<string>();
        statements.Add(
            ExpressionStatement(
                AssignmentExpression(
                    SyntaxKind.SimpleAssignmentExpression,
                    IdentifierName("errors"),
                    ObjectCreationExpression(
                        GenericName("List")
                        .AddTypeArgumentListArguments(
                            PredefinedType(Token(SyntaxKind.StringKeyword))))
                    .WithArgumentList(ArgumentList()))));
        
        // 为每个规则生成验证代码
        foreach (var rule in rules)
        {
            statements.Add(GenerateValidationStatement(rule));
        }
        
        // return errors.Count == 0;
        statements.Add(
            ReturnStatement(
                BinaryExpression(
                    SyntaxKind.EqualsExpression,
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        IdentifierName("errors"),
                        IdentifierName("Count")),
                    LiteralExpression(
                        SyntaxKind.NumericLiteralExpression,
                        Literal(0)))));
        
        return MethodDeclaration(
            PredefinedType(Token(SyntaxKind.BoolKeyword)),
            "Validate")
        .AddModifiers(Token(SyntaxKind.PublicKeyword))
        .AddParameterListParameters(
            Parameter(Identifier("errors"))
            .WithType(
                GenericName("List")
                .AddTypeArgumentListArguments(
                    PredefinedType(Token(SyntaxKind.StringKeyword))))
            .WithModifiers(TokenList(Token(SyntaxKind.OutKeyword))))
        .WithBody(Block(statements));
    }
    
    private StatementSyntax GenerateValidationStatement(ValidationRule rule)
    {
        // if (condition)
        //     errors.Add("error message");
        return IfStatement(
            ParseExpression(rule.Condition),
            ExpressionStatement(
                InvocationExpression(
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        IdentifierName("errors"),
                        IdentifierName("Add")))
                .AddArgumentListArguments(
                    Argument(
                        LiteralExpression(
                            SyntaxKind.StringLiteralExpression,
                            Literal(rule.ErrorMessage))))));
    }
    
    public class ValidationRule
    {
        public string Condition { get; set; }
        public string ErrorMessage { get; set; }
    }
}

案例 3: 生成序列化代码

csharp
/// <summary>
/// 自动生成序列化/反序列化代码
/// </summary>
public class SerializationCodeGenerator
{
    /// <summary>
    /// 生成 JSON 序列化方法
    /// public string ToJson()
    /// {
    ///     return JsonSerializer.Serialize(this);
    /// }
    /// </summary>
    public MethodDeclarationSyntax GenerateToJsonMethod()
    {
        return MethodDeclaration(
            PredefinedType(Token(SyntaxKind.StringKeyword)),
            "ToJson")
        .AddModifiers(Token(SyntaxKind.PublicKeyword))
        .WithBody(Block(
            ReturnStatement(
                InvocationExpression(
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        IdentifierName("JsonSerializer"),
                        IdentifierName("Serialize")))
                .AddArgumentListArguments(
                    Argument(ThisExpression())))));
    }
    
    /// <summary>
    /// 生成 JSON 反序列化方法
    /// public static T FromJson<T>(string json)
    /// {
    ///     return JsonSerializer.Deserialize<T>(json);
    /// }
    /// </summary>
    public MethodDeclarationSyntax GenerateFromJsonMethod()
    {
        return MethodDeclaration(
            IdentifierName("T"),
            "FromJson")
        .AddModifiers(
            Token(SyntaxKind.PublicKeyword),
            Token(SyntaxKind.StaticKeyword))
        .AddTypeParameterListParameters(TypeParameter("T"))
        .AddParameterListParameters(
            Parameter(Identifier("json"))
            .WithType(PredefinedType(Token(SyntaxKind.StringKeyword))))
        .WithBody(Block(
            ReturnStatement(
                InvocationExpression(
                    MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        IdentifierName("JsonSerializer"),
                        GenericName("Deserialize")
                        .AddTypeArgumentListArguments(IdentifierName("T"))))
                .AddArgumentListArguments(
                    Argument(IdentifierName("json"))))));
    }
}

📚 最佳实践总结

✅ 推荐做法

  1. 使用对象池和缓存

    • 缓存常用的 token 和语法节点
    • 重用不可变对象
  2. 批量操作

    • 一次性添加所有成员
    • 避免在循环中逐个添加
  3. 延迟格式化

    • 只在最后格式化一次
    • 避免重复格式化
  4. 使用流式构建器

    • 提高代码可读性
    • 支持链式调用
  5. 编写单元测试

    • 验证生成的代码正确性
    • 使用基准测试优化性能

❌ 避免的做法

  1. 不要在循环中格式化

    • 性能开销大
    • 应该最后统一格式化
  2. 不要逐个添加成员

    • 每次都创建新对象
    • 应该批量添加
  3. 不要忽略边缘情况

    • 保留字需要转义
    • 特殊字符需要处理
  4. 不要过度优化

    • 先保证正确性
    • 再考虑性能优化

🔗 相关资源

API 参考

完整参考

实战示例


⏭️ 下一步

完成本指南后,建议:

  1. 实践项目 - 创建一个复杂的代码生成器
  2. 性能优化 - 使用基准测试优化性能
  3. 学习增量生成 - 掌握增量生成器
  4. 阅读源码 - 研究 Roslyn 源代码

最后更新: 2025-01-21

基于 MIT 许可发布