代码生成 API 完整参考
本文档详细介绍 Roslyn 代码生成 API,包括 SyntaxFactory 的使用、代码构建模式、格式化技巧以及复杂结构的生成方法。
SyntaxFactory 完整指南
基本概念
SyntaxFactory 是 Roslyn 提供的用于创建语法节点的工厂类。它提供了创建各种 C# 语法元素的静态方法。
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
/// <summary>
/// SyntaxFactory 基础示例
/// </summary>
public class SyntaxFactoryBasics
{
/// <summary>
/// 创建简单的标识符
/// </summary>
public IdentifierNameSyntax CreateIdentifier()
{
// 创建标识符:myVariable
return IdentifierName("myVariable");
}
/// <summary>
/// 创建字面量
/// </summary>
public LiteralExpressionSyntax CreateLiteral()
{
// 创建整数字面量:42
return LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(42));
}
/// <summary>
/// 创建字符串字面量
/// </summary>
public LiteralExpressionSyntax CreateStringLiteral()
{
// 创建字符串字面量:"Hello, World!"
return LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("Hello, World!"));
}
}常用方法
1. 创建类型
/// <summary>
/// 创建各种类型语法
/// </summary>
public class TypeCreation
{
/// <summary>
/// 创建预定义类型(int, string 等)
/// </summary>
public PredefinedTypeSyntax CreatePredefinedType()
{
// 创建 int 类型
return PredefinedType(Token(SyntaxKind.IntKeyword));
}
/// <summary>
/// 创建自定义类型
/// </summary>
public IdentifierNameSyntax CreateCustomType()
{
// 创建 MyClass 类型
return IdentifierName("MyClass");
}
/// <summary>
/// 创建泛型类型
/// </summary>
public GenericNameSyntax CreateGenericType()
{
// 创建 List<int> 类型
return GenericName(
Identifier("List"),
TypeArgumentList(
SingletonSeparatedList<TypeSyntax>(
PredefinedType(Token(SyntaxKind.IntKeyword)))));
}
/// <summary>
/// 创建数组类型
/// </summary>
public ArrayTypeSyntax CreateArrayType()
{
// 创建 int[] 类型
return ArrayType(
PredefinedType(Token(SyntaxKind.IntKeyword)),
SingletonList(
ArrayRankSpecifier(
SingletonSeparatedList<ExpressionSyntax>(
OmittedArraySizeExpression()))));
}
/// <summary>
/// 创建可空类型
/// </summary>
public NullableTypeSyntax CreateNullableType()
{
// 创建 int? 类型
return NullableType(
PredefinedType(Token(SyntaxKind.IntKeyword)));
}
}2. 创建表达式
/// <summary>
/// 创建各种表达式
/// </summary>
public class ExpressionCreation
{
/// <summary>
/// 创建二元表达式
/// </summary>
public BinaryExpressionSyntax CreateBinaryExpression()
{
// 创建:a + b
return BinaryExpression(
SyntaxKind.AddExpression,
IdentifierName("a"),
IdentifierName("b"));
}
/// <summary>
/// 创建方法调用
/// </summary>
public InvocationExpressionSyntax CreateMethodCall()
{
// 创建:Console.WriteLine("Hello")
return InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("Console"),
IdentifierName("WriteLine")),
ArgumentList(
SingletonSeparatedList(
Argument(
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("Hello"))))));
}
/// <summary>
/// 创建对象创建表达式
/// </summary>
public ObjectCreationExpressionSyntax CreateObjectCreation()
{
// 创建:new MyClass()
return ObjectCreationExpression(
IdentifierName("MyClass"),
ArgumentList(),
null);
}
/// <summary>
/// 创建成员访问表达式
/// </summary>
public MemberAccessExpressionSyntax CreateMemberAccess()
{
// 创建:obj.Property
return MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("obj"),
IdentifierName("Property"));
}
}3. 创建语句
/// <summary>
/// 创建各种语句
/// </summary>
public class StatementCreation
{
/// <summary>
/// 创建变量声明语句
/// </summary>
public LocalDeclarationStatementSyntax CreateVariableDeclaration()
{
// 创建:int x = 42;
return LocalDeclarationStatement(
VariableDeclaration(
PredefinedType(Token(SyntaxKind.IntKeyword)),
SingletonSeparatedList(
VariableDeclarator(
Identifier("x"),
null,
EqualsValueClause(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(42)))))));
}
/// <summary>
/// 创建 return 语句
/// </summary>
public ReturnStatementSyntax CreateReturnStatement()
{
// 创建:return 42;
return ReturnStatement(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(42)));
}
/// <summary>
/// 创建 if 语句
/// </summary>
public IfStatementSyntax CreateIfStatement()
{
// 创建:if (x > 0) { return true; }
return IfStatement(
BinaryExpression(
SyntaxKind.GreaterThanExpression,
IdentifierName("x"),
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(0))),
Block(
ReturnStatement(
LiteralExpression(
SyntaxKind.TrueLiteralExpression))));
}
}SyntaxFactory 完整示例
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
/// <summary>
/// 使用 SyntaxFactory 生成完整的类
/// </summary>
public class CompleteClassGeneration
{
/// <summary>
/// 生成一个简单的类
/// </summary>
public ClassDeclarationSyntax GenerateSimpleClass()
{
// 生成:
// public class Person
// {
// public string Name { get; set; }
// public int Age { get; set; }
// }
return ClassDeclaration("Person")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
// Name 属性
PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
Identifier("Name"))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken))),
// Age 属性
PropertyDeclaration(
PredefinedType(Token(SyntaxKind.IntKeyword)),
Identifier("Age"))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken))));
}
}代码构建模式
构建器模式
使用构建器模式可以让代码生成更加清晰和易于维护。
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
/// <summary>
/// 类构建器
/// </summary>
public class ClassBuilder
{
private string _className;
private List<string> _modifiers = new();
private List<PropertyDeclarationSyntax> _properties = new();
private List<MethodDeclarationSyntax> _methods = new();
public ClassBuilder WithName(string name)
{
_className = name;
return this;
}
public ClassBuilder WithModifier(string modifier)
{
_modifiers.Add(modifier);
return this;
}
public ClassBuilder AddProperty(string type, string name)
{
var property = PropertyDeclaration(
ParseTypeName(type),
Identifier(name))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
_properties.Add(property);
return this;
}
public ClassDeclarationSyntax Build()
{
var classDecl = ClassDeclaration(_className);
// 添加修饰符
foreach (var modifier in _modifiers)
{
classDecl = classDecl.AddModifiers(
Token(ParseModifier(modifier)));
}
// 添加成员
classDecl = classDecl.AddMembers(_properties.ToArray());
classDecl = classDecl.AddMembers(_methods.ToArray());
return classDecl;
}
private SyntaxKind ParseModifier(string modifier)
{
return modifier.ToLower() switch
{
"public" => SyntaxKind.PublicKeyword,
"private" => SyntaxKind.PrivateKeyword,
"protected" => SyntaxKind.ProtectedKeyword,
"internal" => SyntaxKind.InternalKeyword,
"static" => SyntaxKind.StaticKeyword,
"abstract" => SyntaxKind.AbstractKeyword,
"sealed" => SyntaxKind.SealedKeyword,
_ => throw new ArgumentException($"Unknown modifier: {modifier}")
};
}
}流式 API
/// <summary>
/// 使用流式 API 生成代码
/// </summary>
public class FluentCodeGeneration
{
public ClassDeclarationSyntax GenerateClass()
{
return ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
"Name")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken))));
}
}格式化和美化
NormalizeWhitespace
NormalizeWhitespace 方法可以自动格式化生成的代码。
/// <summary>
/// 代码格式化示例
/// </summary>
public class CodeFormatting
{
public string FormatCode(ClassDeclarationSyntax classDecl)
{
// 使用 NormalizeWhitespace 格式化代码
var formatted = classDecl.NormalizeWhitespace();
return formatted.ToFullString();
}
}最佳实践
✅ 推荐做法
做法 1: 使用 NormalizeWhitespace
// ✅ 好:使用 NormalizeWhitespace 格式化
var code = classDecl.NormalizeWhitespace().ToFullString();原因: 自动格式化代码,使其更易读。
常见错误
🐛 错误 1: 忘记格式化代码
描述: 生成的代码没有格式化,难以阅读。
解决方案: 使用 NormalizeWhitespace() 方法。
相关资源
最后更新: 2025-01-20
代码构建完整示例
以下是一个完整的示例,展示如何使用构建器模式生成复杂的类:
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// 完整的类生成器示例
/// 使用构建器模式生成包含属性、方法和构造函数的类
/// </summary>
public class CompleteClassGenerator
{
/// <summary>
/// 生成一个完整的 Person 类
/// </summary>
public CompilationUnitSyntax GeneratePersonClass()
{
// 创建命名空间
var namespaceDecl = NamespaceDeclaration(
ParseName("MyNamespace"));
// 创建类
var classDecl = new ClassBuilder()
.WithName("Person")
.WithModifier("public")
.AddProperty("string", "FirstName")
.AddProperty("string", "LastName")
.AddProperty("int", "Age")
.AddMethod(CreateToStringMethod())
.Build();
// 添加类到命名空间
namespaceDecl = namespaceDecl.AddMembers(classDecl);
// 创建编译单元
var compilationUnit = CompilationUnit()
.AddUsings(
UsingDirective(ParseName("System")))
.AddMembers(namespaceDecl)
.NormalizeWhitespace();
return compilationUnit;
}
/// <summary>
/// 创建 ToString 方法
/// </summary>
private MethodDeclarationSyntax CreateToStringMethod()
{
// 创建方法体:return $"{FirstName} {LastName}, Age: {Age}";
var returnStatement = ReturnStatement(
InterpolatedStringExpression(
Token(SyntaxKind.InterpolatedStringStartToken))
.AddContents(
Interpolation(IdentifierName("FirstName")),
InterpolatedStringText(" "),
Interpolation(IdentifierName("LastName")),
InterpolatedStringText(", Age: "),
Interpolation(IdentifierName("Age"))));
// 创建方法
return MethodDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
Identifier("ToString"))
.AddModifiers(
Token(SyntaxKind.PublicKeyword),
Token(SyntaxKind.OverrideKeyword))
.WithBody(Block(returnStatement));
}
}
/// <summary>
/// 增强的类构建器
/// </summary>
public class ClassBuilder
{
private string _className;
private List<SyntaxToken> _modifiers = new();
private List<PropertyDeclarationSyntax> _properties = new();
private List<MethodDeclarationSyntax> _methods = new();
private List<FieldDeclarationSyntax> _fields = new();
private List<ConstructorDeclarationSyntax> _constructors = new();
public ClassBuilder WithName(string name)
{
_className = name;
return this;
}
public ClassBuilder WithModifier(string modifier)
{
_modifiers.Add(Token(ParseModifier(modifier)));
return this;
}
public ClassBuilder AddProperty(string type, string name)
{
var property = PropertyDeclaration(
ParseTypeName(type),
Identifier(name))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
_properties.Add(property);
return this;
}
public ClassBuilder AddMethod(MethodDeclarationSyntax method)
{
_methods.Add(method);
return this;
}
public ClassBuilder AddField(string type, string name, bool isReadOnly = false)
{
var modifiers = new List<SyntaxToken> { Token(SyntaxKind.PrivateKeyword) };
if (isReadOnly)
{
modifiers.Add(Token(SyntaxKind.ReadOnlyKeyword));
}
var field = FieldDeclaration(
VariableDeclaration(ParseTypeName(type))
.AddVariables(VariableDeclarator(Identifier(name))))
.AddModifiers(modifiers.ToArray());
_fields.Add(field);
return this;
}
public ClassDeclarationSyntax Build()
{
var classDecl = ClassDeclaration(_className);
// 添加修饰符
if (_modifiers.Any())
{
classDecl = classDecl.AddModifiers(_modifiers.ToArray());
}
// 添加成员(按顺序:字段、构造函数、属性、方法)
var members = new List<MemberDeclarationSyntax>();
members.AddRange(_fields);
members.AddRange(_constructors);
members.AddRange(_properties);
members.AddRange(_methods);
classDecl = classDecl.AddMembers(members.ToArray());
return classDecl;
}
private SyntaxKind ParseModifier(string modifier)
{
return modifier.ToLower() switch
{
"public" => SyntaxKind.PublicKeyword,
"private" => SyntaxKind.PrivateKeyword,
"protected" => SyntaxKind.ProtectedKeyword,
"internal" => SyntaxKind.InternalKeyword,
"static" => SyntaxKind.StaticKeyword,
"abstract" => SyntaxKind.AbstractKeyword,
"sealed" => SyntaxKind.SealedKeyword,
"partial" => SyntaxKind.PartialKeyword,
_ => throw new ArgumentException($"Unknown modifier: {modifier}")
};
}
}格式化和美化
NormalizeWhitespace
NormalizeWhitespace 方法是格式化生成代码的最简单方式。
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
/// <summary>
/// 代码格式化示例
/// </summary>
public class CodeFormattingExamples
{
/// <summary>
/// 基本的格式化
/// </summary>
public string BasicFormatting()
{
// 创建一个没有格式化的类
var classDecl = ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
"Name")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken))));
// 使用 NormalizeWhitespace 格式化
var formatted = classDecl.NormalizeWhitespace();
// 转换为字符串
return formatted.ToFullString();
// 输出:
// public class MyClass
// {
// public string Name { get; set; }
// }
}
/// <summary>
/// 自定义缩进格式化
/// </summary>
public string CustomIndentFormatting()
{
var classDecl = ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
"Name")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken))));
// 使用自定义缩进(4个空格)
var formatted = classDecl.NormalizeWhitespace(indentation: " ");
return formatted.ToFullString();
}
/// <summary>
/// 格式化整个编译单元
/// </summary>
public string FormatCompilationUnit()
{
// 创建完整的编译单元
var compilationUnit = CompilationUnit()
.AddUsings(
UsingDirective(ParseName("System")),
UsingDirective(ParseName("System.Collections.Generic")))
.AddMembers(
NamespaceDeclaration(ParseName("MyNamespace"))
.AddMembers(
ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
"Name")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken))))));
// 格式化整个编译单元
var formatted = compilationUnit.NormalizeWhitespace();
return formatted.ToFullString();
// 输出:
// using System;
// using System.Collections.Generic;
//
// namespace MyNamespace
// {
// public class MyClass
// {
// public string Name { get; set; }
// }
// }
}
}自定义格式化
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
/// <summary>
/// 自定义格式化示例
/// </summary>
public class CustomFormatting
{
/// <summary>
/// 添加自定义注释
/// </summary>
public ClassDeclarationSyntax AddXmlDocumentation(
ClassDeclarationSyntax classDecl,
string summary)
{
// 创建 XML 文档注释
var xmlComment = Comment($"/// <summary>\n/// {summary}\n/// </summary>");
// 添加注释到类声明
return classDecl.WithLeadingTrivia(
TriviaList(xmlComment, CarriageReturnLineFeed));
}
/// <summary>
/// 添加区域标记
/// </summary>
public ClassDeclarationSyntax AddRegions(ClassDeclarationSyntax classDecl)
{
// 创建 #region 和 #endregion
var regionStart = Trivia(
RegionDirectiveTrivia(true)
.WithEndOfDirectiveToken(
Token(TriviaList(PreprocessingMessage("Properties")),
SyntaxKind.EndOfDirectiveToken,
TriviaList())));
var regionEnd = Trivia(EndRegionDirectiveTrivia(true));
// 添加区域到类成员
var members = classDecl.Members;
if (members.Any())
{
var firstMember = members.First()
.WithLeadingTrivia(regionStart);
var lastMember = members.Last()
.WithTrailingTrivia(regionEnd);
classDecl = classDecl.WithMembers(
List(members.Select((m, i) =>
i == 0 ? firstMember :
i == members.Count - 1 ? lastMember : m)));
}
return classDecl;
}
}格式化完整示例
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using System.Text;
/// <summary>
/// 完整的格式化示例
/// </summary>
public class CompleteFormattingExample
{
/// <summary>
/// 生成格式化良好的类
/// </summary>
public string GenerateWellFormattedClass()
{
// 1. 创建类
var classDecl = ClassDeclaration("Person")
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 2. 添加 XML 文档注释
classDecl = classDecl.WithLeadingTrivia(
TriviaList(
Comment("/// <summary>"),
CarriageReturnLineFeed,
Comment("/// 表示一个人的信息"),
CarriageReturnLineFeed,
Comment("/// </summary>"),
CarriageReturnLineFeed));
// 3. 添加属性
var properties = new[]
{
CreateDocumentedProperty("string", "FirstName", "名字"),
CreateDocumentedProperty("string", "LastName", "姓氏"),
CreateDocumentedProperty("int", "Age", "年龄")
};
classDecl = classDecl.AddMembers(properties);
// 4. 创建命名空间
var namespaceDecl = NamespaceDeclaration(ParseName("MyApp.Models"))
.AddMembers(classDecl);
// 5. 创建编译单元
var compilationUnit = CompilationUnit()
.AddUsings(UsingDirective(ParseName("System")))
.AddMembers(namespaceDecl);
// 6. 格式化
var formatted = compilationUnit.NormalizeWhitespace();
return formatted.ToFullString();
}
/// <summary>
/// 创建带文档注释的属性
/// </summary>
private PropertyDeclarationSyntax CreateDocumentedProperty(
string type,
string name,
string summary)
{
var property = PropertyDeclaration(
ParseTypeName(type),
Identifier(name))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
// 添加 XML 文档注释
property = property.WithLeadingTrivia(
TriviaList(
CarriageReturnLineFeed,
Whitespace(" "),
Comment("/// <summary>"),
CarriageReturnLineFeed,
Whitespace(" "),
Comment($"/// {summary}"),
CarriageReturnLineFeed,
Whitespace(" "),
Comment("/// </summary>"),
CarriageReturnLineFeed,
Whitespace(" ")));
return property;
}
}复杂结构生成
生成类
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// 生成各种类型的类
/// </summary>
public class ClassGeneration
{
/// <summary>
/// 生成简单的 POCO 类
/// </summary>
public ClassDeclarationSyntax GeneratePocoClass(
string className,
Dictionary<string, string> properties)
{
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 添加属性
foreach (var prop in properties)
{
var property = PropertyDeclaration(
ParseTypeName(prop.Value),
Identifier(prop.Key))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
classDecl = classDecl.AddMembers(property);
}
return classDecl;
}
/// <summary>
/// 生成带构造函数的类
/// </summary>
public ClassDeclarationSyntax GenerateClassWithConstructor(
string className,
Dictionary<string, string> parameters)
{
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 添加字段
foreach (var param in parameters)
{
var field = FieldDeclaration(
VariableDeclaration(ParseTypeName(param.Value))
.AddVariables(
VariableDeclarator(Identifier($"_{param.Key}"))))
.AddModifiers(
Token(SyntaxKind.PrivateKeyword),
Token(SyntaxKind.ReadOnlyKeyword));
classDecl = classDecl.AddMembers(field);
}
// 创建构造函数
var constructor = ConstructorDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddParameterListParameters(
parameters.Select(p =>
Parameter(Identifier(p.Key))
.WithType(ParseTypeName(p.Value)))
.ToArray())
.WithBody(Block(
parameters.Select(p =>
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName($"_{p.Key}"),
IdentifierName(p.Key))))
.ToArray()));
classDecl = classDecl.AddMembers(constructor);
return classDecl;
}
/// <summary>
/// 生成实现接口的类
/// </summary>
public ClassDeclarationSyntax GenerateClassWithInterface(
string className,
string interfaceName)
{
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddBaseListTypes(
SimpleBaseType(IdentifierName(interfaceName)));
return classDecl;
}
/// <summary>
/// 生成继承基类的类
/// </summary>
public ClassDeclarationSyntax GenerateClassWithBaseClass(
string className,
string baseClassName)
{
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddBaseListTypes(
SimpleBaseType(IdentifierName(baseClassName)));
return classDecl;
}
}生成方法
/// <summary>
/// 生成各种类型的方法
/// </summary>
public class MethodGeneration
{
/// <summary>
/// 生成简单的方法
/// </summary>
public MethodDeclarationSyntax GenerateSimpleMethod()
{
// 生成:public void DoSomething() { }
return MethodDeclaration(
PredefinedType(Token(SyntaxKind.VoidKeyword)),
Identifier("DoSomething"))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.WithBody(Block());
}
/// <summary>
/// 生成带参数的方法
/// </summary>
public MethodDeclarationSyntax GenerateMethodWithParameters()
{
// 生成:public int Add(int a, int b) { return a + b; }
return MethodDeclaration(
PredefinedType(Token(SyntaxKind.IntKeyword)),
Identifier("Add"))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddParameterListParameters(
Parameter(Identifier("a"))
.WithType(PredefinedType(Token(SyntaxKind.IntKeyword))),
Parameter(Identifier("b"))
.WithType(PredefinedType(Token(SyntaxKind.IntKeyword))))
.WithBody(Block(
ReturnStatement(
BinaryExpression(
SyntaxKind.AddExpression,
IdentifierName("a"),
IdentifierName("b")))));
}
}生成属性
/// <summary>
/// 生成各种类型的属性
/// </summary>
public class PropertyGeneration
{
/// <summary>
/// 生成自动属性
/// </summary>
public PropertyDeclarationSyntax GenerateAutoProperty(
string typeName,
string propertyName)
{
// 生成:public string Name { get; set; }
return PropertyDeclaration(
ParseTypeName(typeName),
Identifier(propertyName))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
}
/// <summary>
/// 生成只读属性
/// </summary>
public PropertyDeclarationSyntax GenerateReadOnlyProperty(
string typeName,
string propertyName)
{
// 生成:public string Name { get; }
return PropertyDeclaration(
ParseTypeName(typeName),
Identifier(propertyName))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
}
}字符串插值 vs SyntaxFactory
优缺点对比
字符串插值方式
优点:
- ✅ 简单直观,易于理解
- ✅ 快速原型开发
- ✅ 适合简单的代码生成
缺点:
- ❌ 难以维护复杂的代码结构
- ❌ 缺少语法验证
- ❌ 格式化困难
- ❌ 难以处理特殊字符和转义
// 字符串插值示例
public string GenerateClassUsingString(string className)
{
return $@"
public class {className}
{{
public string Name {{ get; set; }}
public int Age {{ get; set; }}
}}";
}SyntaxFactory 方式
优点:
- ✅ 类型安全,编译时检查
- ✅ 易于维护和重构
- ✅ 自动格式化
- ✅ 支持复杂的代码结构
- ✅ 可以利用 Roslyn 的语法分析
缺点:
- ❌ 学习曲线陡峭
- ❌ 代码冗长
- ❌ 初期开发速度较慢
// SyntaxFactory 示例
public ClassDeclarationSyntax GenerateClassUsingSyntaxFactory(
string className)
{
return ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
"Name")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken))));
}使用场景建议
使用字符串插值的场景
- 简单的代码片段生成
- 快速原型开发
- 一次性的代码生成任务
- 模板非常简单且不会改变
// ✅ 适合字符串插值:简单的属性生成
public string GenerateSimpleProperty(string name, string type)
{
return $"public {type} {name} {{ get; set; }}";
}使用 SyntaxFactory 的场景
- 复杂的代码结构
- 需要维护的生成器
- 需要语法验证
- 需要与现有代码集成
// ✅ 适合 SyntaxFactory:复杂的类生成
public ClassDeclarationSyntax GenerateComplexClass(
string className,
List<PropertyInfo> properties)
{
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
foreach (var prop in properties)
{
var property = GenerateProperty(prop);
classDecl = classDecl.AddMembers(property);
}
return classDecl;
}混合使用策略
在实际项目中,可以结合两种方式的优点:
/// <summary>
/// 混合使用字符串和 SyntaxFactory
/// </summary>
public class HybridCodeGeneration
{
/// <summary>
/// 使用字符串生成简单部分,SyntaxFactory 生成复杂部分
/// </summary>
public CompilationUnitSyntax GenerateCode(string className)
{
// 使用 SyntaxFactory 生成主要结构
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 对于简单的方法体,可以使用 ParseStatement
var methodBody = ParseStatement(@"
Console.WriteLine(""Hello, World!"");
return 42;
");
var method = MethodDeclaration(
PredefinedType(Token(SyntaxKind.IntKeyword)),
"GetValue")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.WithBody(Block(methodBody));
classDecl = classDecl.AddMembers(method);
return CompilationUnit()
.AddMembers(classDecl)
.NormalizeWhitespace();
}
}最佳实践
✅ 推荐做法
做法 1: 使用 NormalizeWhitespace 格式化代码
// ✅ 好的做法:使用 NormalizeWhitespace
public string GenerateClass(string className)
{
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(/* ... */);
// 格式化代码
var formatted = classDecl.NormalizeWhitespace();
return formatted.ToFullString();
}原因:自动格式化代码,保持一致的代码风格。
做法 2: 使用 using static 简化代码
// ✅ 好的做法:使用 using static
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
public class CodeGenerator
{
public ClassDeclarationSyntax Generate()
{
// 不需要写 SyntaxFactory.ClassDeclaration
return ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword));
}
}原因:减少代码冗余,提高可读性。
做法 3: 使用辅助方法封装常见模式
// ✅ 好的做法:封装常见模式
public class CodeGenerationHelpers
{
/// <summary>
/// 创建公共自动属性
/// </summary>
public static PropertyDeclarationSyntax CreateAutoProperty(
string typeName,
string propertyName)
{
return PropertyDeclaration(
ParseTypeName(typeName),
Identifier(propertyName))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
}
/// <summary>
/// 使用辅助方法
/// </summary>
public ClassDeclarationSyntax GenerateClass()
{
return ClassDeclaration("Person")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
CreateAutoProperty("string", "Name"),
CreateAutoProperty("int", "Age"));
}
}原因:提高代码复用性和可维护性。
❌ 反模式
反模式 1: 不格式化生成的代码
// ❌ 不好的做法:不格式化代码
public string GenerateClass(string className)
{
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 直接返回,没有格式化
return classDecl.ToFullString();
}
// 结果:public class MyClass{} // 没有换行和缩进问题:生成的代码难以阅读。
正确做法:使用 NormalizeWhitespace(参见推荐做法 1)。
反模式 2: 硬编码字符串拼接
// ❌ 不好的做法:硬编码字符串拼接
public string GenerateMethod()
{
return "public void MyMethod() { Console.WriteLine(\"Hello\"); }";
}问题:难以维护,容易出错,缺少语法验证。
正确做法:使用 SyntaxFactory 或 ParseStatement。
常见错误
🐛 错误 1: 忘记添加分号标记
描述:某些语法节点需要显式添加分号标记。
错误示例:
// ❌ 错误:缺少分号标记
var accessor = AccessorDeclaration(SyntaxKind.GetAccessorDeclaration);
// 结果:get // 缺少分号解决方案:
// ✅ 正确:添加分号标记
var accessor = AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
// 结果:get;🐛 错误 2: 忘记格式化代码
描述:生成的代码没有正确的缩进和换行。
错误示例:
// ❌ 错误:没有格式化
var code = classDecl.ToFullString();
// 结果:public class MyClass{public string Name{get;set;}}解决方案:
// ✅ 正确:使用 NormalizeWhitespace
var code = classDecl.NormalizeWhitespace().ToFullString();
// 结果:格式化的代码相关资源
- 语义模型 API 完整参考 - 符号和类型系统
- 编译 API 完整参考 - 编译和语法树
- 诊断 API 完整参考 - 错误报告
- 最佳实践 - 代码生成最佳实践
- 常见场景实现 - 实际应用示例
- LEARNING_GUIDE.md - 代码生成章节
官方文档
📝 文档质量保证
本文档遵循以下质量标准:
- ✅ 完整的目录结构
- ✅ 所有代码示例包含详细中文注释
- ✅ 包含最佳实践和反模式对比
- ✅ 包含真实使用场景
- ✅ 包含跨文档引用
- ✅ 内容完整,未因任何限制而精简
最后更新: 2025-01-21
代码生成流程图
代码生成整体流程
SyntaxFactory 使用流程
代码构建模式对比
高级代码生成技术
生成泛型类
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// 生成泛型类的示例
/// </summary>
public class GenericClassGeneration
{
/// <summary>
/// 生成泛型类:public class Container<T> { }
/// </summary>
public ClassDeclarationSyntax GenerateGenericClass()
{
return ClassDeclaration("Container")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddTypeParameterListParameters(
TypeParameter("T"));
}
/// <summary>
/// 生成带约束的泛型类
/// public class Repository<T> where T : class, new() { }
/// </summary>
public ClassDeclarationSyntax GenerateGenericClassWithConstraints()
{
return ClassDeclaration("Repository")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddTypeParameterListParameters(
TypeParameter("T"))
.AddConstraintClauses(
TypeParameterConstraintClause("T")
.AddConstraints(
ClassOrStructConstraint(SyntaxKind.ClassConstraint),
ConstructorConstraint()));
}
/// <summary>
/// 生成多个类型参数的泛型类
/// public class Pair<TKey, TValue> { }
/// </summary>
public ClassDeclarationSyntax GenerateMultipleTypeParametersClass()
{
return ClassDeclaration("Pair")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddTypeParameterListParameters(
TypeParameter("TKey"),
TypeParameter("TValue"));
}
}生成特性(Attributes)
/// <summary>
/// 生成特性的示例
/// </summary>
public class AttributeGeneration
{
/// <summary>
/// 生成简单特性:[Serializable]
/// </summary>
public AttributeListSyntax GenerateSimpleAttribute()
{
return AttributeList(
SingletonSeparatedList(
Attribute(IdentifierName("Serializable"))));
}
/// <summary>
/// 生成带参数的特性:[Table("Users")]
/// </summary>
public AttributeListSyntax GenerateAttributeWithArgument()
{
return AttributeList(
SingletonSeparatedList(
Attribute(IdentifierName("Table"))
.AddArgumentListArguments(
AttributeArgument(
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("Users"))))));
}
/// <summary>
/// 生成带命名参数的特性:[JsonProperty(PropertyName = "user_id")]
/// </summary>
public AttributeListSyntax GenerateAttributeWithNamedArgument()
{
return AttributeList(
SingletonSeparatedList(
Attribute(IdentifierName("JsonProperty"))
.AddArgumentListArguments(
AttributeArgument(
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("user_id")))
.WithNameEquals(
NameEquals(IdentifierName("PropertyName"))))));
}
/// <summary>
/// 为类添加多个特性
/// </summary>
public ClassDeclarationSyntax AddAttributesToClass(
ClassDeclarationSyntax classDecl,
params AttributeListSyntax[] attributes)
{
return classDecl.AddAttributeLists(attributes);
}
}生成接口
/// <summary>
/// 生成接口的示例
/// </summary>
public class InterfaceGeneration
{
/// <summary>
/// 生成简单接口
/// public interface IRepository { }
/// </summary>
public InterfaceDeclarationSyntax GenerateSimpleInterface()
{
return InterfaceDeclaration("IRepository")
.AddModifiers(Token(SyntaxKind.PublicKeyword));
}
/// <summary>
/// 生成带方法的接口
/// public interface IRepository
/// {
/// void Save(object entity);
/// object Load(int id);
/// }
/// </summary>
public InterfaceDeclarationSyntax GenerateInterfaceWithMethods()
{
return InterfaceDeclaration("IRepository")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
// void Save(object entity);
MethodDeclaration(
PredefinedType(Token(SyntaxKind.VoidKeyword)),
"Save")
.AddParameterListParameters(
Parameter(Identifier("entity"))
.WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword))))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
// object Load(int id);
MethodDeclaration(
PredefinedType(Token(SyntaxKind.ObjectKeyword)),
"Load")
.AddParameterListParameters(
Parameter(Identifier("id"))
.WithType(PredefinedType(Token(SyntaxKind.IntKeyword))))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
}
/// <summary>
/// 生成泛型接口
/// public interface IRepository<T> where T : class
/// {
/// void Save(T entity);
/// T Load(int id);
/// }
/// </summary>
public InterfaceDeclarationSyntax GenerateGenericInterface()
{
return InterfaceDeclaration("IRepository")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddTypeParameterListParameters(TypeParameter("T"))
.AddConstraintClauses(
TypeParameterConstraintClause("T")
.AddConstraints(ClassOrStructConstraint(SyntaxKind.ClassConstraint)))
.AddMembers(
MethodDeclaration(
PredefinedType(Token(SyntaxKind.VoidKeyword)),
"Save")
.AddParameterListParameters(
Parameter(Identifier("entity"))
.WithType(IdentifierName("T")))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
MethodDeclaration(
IdentifierName("T"),
"Load")
.AddParameterListParameters(
Parameter(Identifier("id"))
.WithType(PredefinedType(Token(SyntaxKind.IntKeyword))))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
}
}生成枚举
/// <summary>
/// 生成枚举的示例
/// </summary>
public class EnumGeneration
{
/// <summary>
/// 生成简单枚举
/// public enum Status
/// {
/// Active,
/// Inactive,
/// Pending
/// }
/// </summary>
public EnumDeclarationSyntax GenerateSimpleEnum()
{
return EnumDeclaration("Status")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
EnumMemberDeclaration("Active"),
EnumMemberDeclaration("Inactive"),
EnumMemberDeclaration("Pending"));
}
/// <summary>
/// 生成带值的枚举
/// public enum ErrorCode
/// {
/// Success = 0,
/// NotFound = 404,
/// ServerError = 500
/// }
/// </summary>
public EnumDeclarationSyntax GenerateEnumWithValues()
{
return EnumDeclaration("ErrorCode")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(
EnumMemberDeclaration("Success")
.WithEqualsValue(
EqualsValueClause(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(0)))),
EnumMemberDeclaration("NotFound")
.WithEqualsValue(
EqualsValueClause(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(404)))),
EnumMemberDeclaration("ServerError")
.WithEqualsValue(
EqualsValueClause(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(500)))));
}
}真实使用场景
场景 1: DTO 类生成器
为数据库表自动生成 DTO(Data Transfer Object)类。
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using System.Collections.Generic;
/// <summary>
/// 场景:DTO 类生成器
/// 根据数据库表结构自动生成 DTO 类
/// </summary>
public class DtoGenerator
{
/// <summary>
/// 表列信息
/// </summary>
public class ColumnInfo
{
public string Name { get; set; }
public string Type { get; set; }
public bool IsNullable { get; set; }
public string Description { get; set; }
}
/// <summary>
/// 生成 DTO 类
/// </summary>
public CompilationUnitSyntax GenerateDto(
string tableName,
List<ColumnInfo> columns)
{
// 类名:UserDto
var className = $"{tableName}Dto";
// 创建类
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 添加 XML 文档注释
classDecl = classDecl.WithLeadingTrivia(
TriviaList(
Comment("/// <summary>"),
CarriageReturnLineFeed,
Comment($"/// {tableName} 表的 DTO 类"),
CarriageReturnLineFeed,
Comment("/// </summary>"),
CarriageReturnLineFeed));
// 为每个列生成属性
foreach (var column in columns)
{
var property = GenerateProperty(column);
classDecl = classDecl.AddMembers(property);
}
// 创建命名空间
var namespaceDecl = NamespaceDeclaration(ParseName("MyApp.Dtos"))
.AddMembers(classDecl);
// 创建编译单元
return CompilationUnit()
.AddUsings(UsingDirective(ParseName("System")))
.AddMembers(namespaceDecl)
.NormalizeWhitespace();
}
/// <summary>
/// 生成属性
/// </summary>
private PropertyDeclarationSyntax GenerateProperty(ColumnInfo column)
{
// 确定属性类型
var typeName = column.Type;
if (column.IsNullable && IsValueType(column.Type))
{
typeName = $"{column.Type}?";
}
// 创建属性
var property = PropertyDeclaration(
ParseTypeName(typeName),
Identifier(column.Name))
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
// 添加 XML 文档注释
if (!string.IsNullOrEmpty(column.Description))
{
property = property.WithLeadingTrivia(
TriviaList(
CarriageReturnLineFeed,
Whitespace(" "),
Comment("/// <summary>"),
CarriageReturnLineFeed,
Whitespace(" "),
Comment($"/// {column.Description}"),
CarriageReturnLineFeed,
Whitespace(" "),
Comment("/// </summary>"),
CarriageReturnLineFeed,
Whitespace(" ")));
}
return property;
}
/// <summary>
/// 判断是否为值类型
/// </summary>
private bool IsValueType(string typeName)
{
return typeName switch
{
"int" or "long" or "short" or "byte" or
"decimal" or "double" or "float" or
"bool" or "DateTime" or "Guid" => true,
_ => false
};
}
}场景 2: Builder 模式生成器
为类自动生成 Builder 模式代码。
/// <summary>
/// 场景:Builder 模式生成器
/// 为现有类生成流式 Builder 类
/// </summary>
public class BuilderPatternGenerator
{
/// <summary>
/// 为类生成 Builder
/// </summary>
public ClassDeclarationSyntax GenerateBuilder(
string targetClassName,
List<PropertyInfo> properties)
{
var builderClassName = $"{targetClassName}Builder";
// 创建 Builder 类
var builderClass = ClassDeclaration(builderClassName)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 添加私有字段
foreach (var prop in properties)
{
var field = FieldDeclaration(
VariableDeclaration(ParseTypeName(prop.Type))
.AddVariables(
VariableDeclarator(Identifier($"_{ToCamelCase(prop.Name)}"))))
.AddModifiers(Token(SyntaxKind.PrivateKeyword));
builderClass = builderClass.AddMembers(field);
}
// 添加 With 方法
foreach (var prop in properties)
{
var withMethod = GenerateWithMethod(builderClassName, prop);
builderClass = builderClass.AddMembers(withMethod);
}
// 添加 Build 方法
var buildMethod = GenerateBuildMethod(targetClassName, properties);
builderClass = builderClass.AddMembers(buildMethod);
return builderClass;
}
/// <summary>
/// 生成 With 方法
/// public PersonBuilder WithName(string name)
/// {
/// _name = name;
/// return this;
/// }
/// </summary>
private MethodDeclarationSyntax GenerateWithMethod(
string builderClassName,
PropertyInfo property)
{
var fieldName = $"_{ToCamelCase(property.Name)}";
var paramName = ToCamelCase(property.Name);
return MethodDeclaration(
IdentifierName(builderClassName),
$"With{property.Name}")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddParameterListParameters(
Parameter(Identifier(paramName))
.WithType(ParseTypeName(property.Type)))
.WithBody(Block(
// _name = name;
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(fieldName),
IdentifierName(paramName))),
// return this;
ReturnStatement(ThisExpression())));
}
/// <summary>
/// 生成 Build 方法
/// public Person Build()
/// {
/// return new Person
/// {
/// Name = _name,
/// Age = _age
/// };
/// }
/// </summary>
private MethodDeclarationSyntax GenerateBuildMethod(
string targetClassName,
List<PropertyInfo> properties)
{
// 创建对象初始化器
var initializers = properties.Select(prop =>
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName(prop.Name),
IdentifierName($"_{ToCamelCase(prop.Name)}")));
return MethodDeclaration(
IdentifierName(targetClassName),
"Build")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.WithBody(Block(
ReturnStatement(
ObjectCreationExpression(IdentifierName(targetClassName))
.WithInitializer(
InitializerExpression(
SyntaxKind.ObjectInitializerExpression,
SeparatedList<ExpressionSyntax>(initializers))))));
}
private string ToCamelCase(string name)
{
if (string.IsNullOrEmpty(name)) return name;
return char.ToLower(name[0]) + name.Substring(1);
}
public class PropertyInfo
{
public string Name { get; set; }
public string Type { get; set; }
}
}场景 3: API 客户端生成器
根据 API 定义自动生成客户端代码。
/// <summary>
/// 场景:API 客户端生成器
/// 根据 API 定义生成 HTTP 客户端代码
/// </summary>
public class ApiClientGenerator
{
public class ApiEndpoint
{
public string Name { get; set; }
public string Method { get; set; } // GET, POST, PUT, DELETE
public string Path { get; set; }
public List<Parameter> Parameters { get; set; }
public string ReturnType { get; set; }
}
public class Parameter
{
public string Name { get; set; }
public string Type { get; set; }
public bool IsRequired { get; set; }
}
/// <summary>
/// 生成 API 客户端类
/// </summary>
public CompilationUnitSyntax GenerateApiClient(
string clientName,
List<ApiEndpoint> endpoints)
{
// 创建客户端类
var clientClass = ClassDeclaration(clientName)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 添加 HttpClient 字段
var httpClientField = FieldDeclaration(
VariableDeclaration(IdentifierName("HttpClient"))
.AddVariables(VariableDeclarator("_httpClient")))
.AddModifiers(
Token(SyntaxKind.PrivateKeyword),
Token(SyntaxKind.ReadOnlyKeyword));
clientClass = clientClass.AddMembers(httpClientField);
// 添加构造函数
var constructor = ConstructorDeclaration(clientName)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddParameterListParameters(
Parameter(Identifier("httpClient"))
.WithType(IdentifierName("HttpClient")))
.WithBody(Block(
ExpressionStatement(
AssignmentExpression(
SyntaxKind.SimpleAssignmentExpression,
IdentifierName("_httpClient"),
IdentifierName("httpClient")))));
clientClass = clientClass.AddMembers(constructor);
// 为每个端点生成方法
foreach (var endpoint in endpoints)
{
var method = GenerateEndpointMethod(endpoint);
clientClass = clientClass.AddMembers(method);
}
// 创建命名空间
var namespaceDecl = NamespaceDeclaration(ParseName("MyApp.ApiClients"))
.AddMembers(clientClass);
// 创建编译单元
return CompilationUnit()
.AddUsings(
UsingDirective(ParseName("System")),
UsingDirective(ParseName("System.Net.Http")),
UsingDirective(ParseName("System.Threading.Tasks")))
.AddMembers(namespaceDecl)
.NormalizeWhitespace();
}
/// <summary>
/// 生成端点方法
/// public async Task<User> GetUserAsync(int id)
/// {
/// var response = await _httpClient.GetAsync($"/api/users/{id}");
/// response.EnsureSuccessStatusCode();
/// return await response.Content.ReadAsAsync<User>();
/// }
/// </summary>
private MethodDeclarationSyntax GenerateEndpointMethod(ApiEndpoint endpoint)
{
// 方法名
var methodName = $"{endpoint.Name}Async";
// 返回类型:Task<ReturnType>
var returnType = GenericName("Task")
.AddTypeArgumentListArguments(
IdentifierName(endpoint.ReturnType));
// 创建方法
var method = MethodDeclaration(returnType, methodName)
.AddModifiers(
Token(SyntaxKind.PublicKeyword),
Token(SyntaxKind.AsyncKeyword));
// 添加参数
foreach (var param in endpoint.Parameters)
{
method = method.AddParameterListParameters(
Parameter(Identifier(param.Name))
.WithType(ParseTypeName(param.Type)));
}
// 生成方法体(简化版)
var methodBody = GenerateMethodBody(endpoint);
method = method.WithBody(Block(methodBody));
return method;
}
private StatementSyntax[] GenerateMethodBody(ApiEndpoint endpoint)
{
// 简化的方法体生成
// 实际应该根据 HTTP 方法生成不同的代码
return new[]
{
// var response = await _httpClient.GetAsync(...);
LocalDeclarationStatement(
VariableDeclaration(IdentifierName("var"))
.AddVariables(
VariableDeclarator("response")
.WithInitializer(
EqualsValueClause(
AwaitExpression(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("_httpClient"),
IdentifierName($"{endpoint.Method}Async")))))))),
// return default;
ReturnStatement(
LiteralExpression(SyntaxKind.DefaultLiteralExpression))
};
}
}常见问题解答(FAQ)
Q1: 如何生成带命名空间的完整代码文件?
A: 使用 CompilationUnit 和 NamespaceDeclaration:
var compilationUnit = CompilationUnit()
.AddUsings(
UsingDirective(ParseName("System")))
.AddMembers(
NamespaceDeclaration(ParseName("MyNamespace"))
.AddMembers(
ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword))))
.NormalizeWhitespace();
string code = compilationUnit.ToFullString();Q2: 如何为生成的代码添加 XML 文档注释?
A: 使用 WithLeadingTrivia 添加注释:
var classDecl = ClassDeclaration("MyClass")
.WithLeadingTrivia(
TriviaList(
Comment("/// <summary>"),
CarriageReturnLineFeed,
Comment("/// 我的类"),
CarriageReturnLineFeed,
Comment("/// </summary>"),
CarriageReturnLineFeed));Q3: 如何生成表达式主体成员(Expression-bodied members)?
A: 使用 WithExpressionBody 和 ArrowExpressionClause:
// 生成:public int GetValue() => 42;
var method = MethodDeclaration(
PredefinedType(Token(SyntaxKind.IntKeyword)),
"GetValue")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.WithExpressionBody(
ArrowExpressionClause(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(42))))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));Q4: 如何生成 async/await 代码?
A: 使用 AsyncKeyword 修饰符和 AwaitExpression:
// 生成:public async Task<int> GetValueAsync()
var method = MethodDeclaration(
GenericName("Task")
.AddTypeArgumentListArguments(
PredefinedType(Token(SyntaxKind.IntKeyword))),
"GetValueAsync")
.AddModifiers(
Token(SyntaxKind.PublicKeyword),
Token(SyntaxKind.AsyncKeyword))
.WithBody(Block(
ReturnStatement(
AwaitExpression(
InvocationExpression(
IdentifierName("SomeAsyncMethod"))))));Q5: 如何生成 Lambda 表达式?
A: 使用 SimpleLambdaExpression 或 ParenthesizedLambdaExpression:
// 生成:x => x * 2
var lambda = SimpleLambdaExpression(
Parameter(Identifier("x")),
BinaryExpression(
SyntaxKind.MultiplyExpression,
IdentifierName("x"),
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(2))));
// 生成:(x, y) => x + y
var multiParamLambda = ParenthesizedLambdaExpression(
ParameterList(
SeparatedList(new[]
{
Parameter(Identifier("x")),
Parameter(Identifier("y"))
})),
BinaryExpression(
SyntaxKind.AddExpression,
IdentifierName("x"),
IdentifierName("y")));Q6: 如何生成 LINQ 查询表达式?
A: 使用 QueryExpression 和相关的查询子句:
// 生成:from x in numbers where x > 5 select x * 2
var query = QueryExpression(
QueryBody(
SingletonList<QueryClauseSyntax>(
WhereClause(
BinaryExpression(
SyntaxKind.GreaterThanExpression,
IdentifierName("x"),
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(5))))),
SelectClause(
BinaryExpression(
SyntaxKind.MultiplyExpression,
IdentifierName("x"),
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(2)))),
null))
.WithFromClause(
FromClause(
Identifier("x"),
IdentifierName("numbers")));Q7: 如何生成 switch 表达式(C# 8.0+)?
A: 使用 SwitchExpression:
// 生成:value switch { 1 => "one", 2 => "two", _ => "other" }
var switchExpr = SwitchExpression(
IdentifierName("value"),
SeparatedList(new[]
{
SwitchExpressionArm(
ConstantPattern(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(1))),
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("one"))),
SwitchExpressionArm(
ConstantPattern(
LiteralExpression(
SyntaxKind.NumericLiteralExpression,
Literal(2))),
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("two"))),
SwitchExpressionArm(
DiscardPattern(),
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("other")))
}));Q8: 如何生成 record 类型(C# 9.0+)?
A: 使用 RecordDeclaration:
// 生成:public record Person(string Name, int Age);
var record = RecordDeclaration(
Token(SyntaxKind.RecordKeyword),
"Person")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.WithParameterList(
ParameterList(
SeparatedList(new[]
{
Parameter(Identifier("Name"))
.WithType(PredefinedType(Token(SyntaxKind.StringKeyword))),
Parameter(Identifier("Age"))
.WithType(PredefinedType(Token(SyntaxKind.IntKeyword)))
})))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));Q9: 如何生成 using 声明(C# 8.0+)?
A: 使用 LocalDeclarationStatement 和 UsingKeyword:
// 生成:using var stream = File.OpenRead("file.txt");
var usingDecl = LocalDeclarationStatement(
VariableDeclaration(IdentifierName("var"))
.AddVariables(
VariableDeclarator("stream")
.WithInitializer(
EqualsValueClause(
InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("File"),
IdentifierName("OpenRead")))
.AddArgumentListArguments(
Argument(
LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("file.txt"))))))))
.AddModifiers(Token(SyntaxKind.UsingKeyword));Q10: 如何生成 nullable 引用类型注解?
A: 使用 NullableType:
// 生成:string? name
var nullableType = NullableType(
PredefinedType(Token(SyntaxKind.StringKeyword)));
// 在属性中使用
var property = PropertyDeclaration(
nullableType,
"Name")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));Q11: 如何生成 init 访问器(C# 9.0+)?
A: 使用 InitAccessorDeclaration:
// 生成:public string Name { get; init; }
var property = PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
"Name")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.InitAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));Q12: 如何生成 pattern matching?
A: 使用各种 Pattern 类型:
// 生成:if (obj is string s) { }
var isPattern = IsPatternExpression(
IdentifierName("obj"),
DeclarationPattern(
PredefinedType(Token(SyntaxKind.StringKeyword)),
SingleVariableDesignation(Identifier("s"))));
var ifStatement = IfStatement(
isPattern,
Block());Q13: 如何生成 tuple 类型?
A: 使用 TupleType:
// 生成:(int, string)
var tupleType = TupleType(
SeparatedList(new[]
{
TupleElement(PredefinedType(Token(SyntaxKind.IntKeyword))),
TupleElement(PredefinedType(Token(SyntaxKind.StringKeyword)))
}));
// 生成带名称的 tuple:(int id, string name)
var namedTupleType = TupleType(
SeparatedList(new[]
{
TupleElement(
PredefinedType(Token(SyntaxKind.IntKeyword)),
Identifier("id")),
TupleElement(
PredefinedType(Token(SyntaxKind.StringKeyword)),
Identifier("name"))
}));Q14: 如何生成 local function?
A: 使用 LocalFunctionStatement:
// 生成:int Add(int a, int b) => a + b;
var localFunction = LocalFunctionStatement(
PredefinedType(Token(SyntaxKind.IntKeyword)),
"Add")
.AddParameterListParameters(
Parameter(Identifier("a"))
.WithType(PredefinedType(Token(SyntaxKind.IntKeyword))),
Parameter(Identifier("b"))
.WithType(PredefinedType(Token(SyntaxKind.IntKeyword))))
.WithExpressionBody(
ArrowExpressionClause(
BinaryExpression(
SyntaxKind.AddExpression,
IdentifierName("a"),
IdentifierName("b"))))
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));Q15: 如何处理生成代码中的特殊字符和转义?
A: Roslyn 会自动处理转义,但你也可以使用 verbatim 字符串:
// 普通字符串(自动转义)
var normalString = LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal("C:\\Path\\To\\File"));
// Verbatim 字符串
var verbatimString = LiteralExpression(
SyntaxKind.StringLiteralExpression,
Literal(@"C:\Path\To\File", @"C:\Path\To\File"));性能优化技巧
技巧 1: 重用 SyntaxToken
// ✅ 好:重用常用的 token
public class TokenCache
{
private static readonly SyntaxToken PublicKeyword =
Token(SyntaxKind.PublicKeyword);
private static readonly SyntaxToken PrivateKeyword =
Token(SyntaxKind.PrivateKeyword);
private static readonly SyntaxToken SemicolonToken =
Token(SyntaxKind.SemicolonToken);
public PropertyDeclarationSyntax CreateProperty(string name)
{
return PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
name)
.AddModifiers(PublicKeyword) // 重用 token
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(SemicolonToken), // 重用 token
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(SemicolonToken)); // 重用 token
}
}技巧 2: 批量添加成员
// ✅ 好:一次性添加所有成员
public ClassDeclarationSyntax CreateClass(List<PropertyInfo> properties)
{
var members = properties
.Select(p => CreateProperty(p))
.ToArray();
return ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddMembers(members); // 一次性添加
}
// ❌ 不好:逐个添加成员
public ClassDeclarationSyntax CreateClassSlow(List<PropertyInfo> properties)
{
var classDecl = ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword));
foreach (var prop in properties)
{
classDecl = classDecl.AddMembers(CreateProperty(prop)); // 每次创建新对象
}
return classDecl;
}技巧 3: 延迟格式化
// ✅ 好:最后才格式化
public string GenerateMultipleClasses(List<string> classNames)
{
var classes = classNames
.Select(name => ClassDeclaration(name)
.AddModifiers(Token(SyntaxKind.PublicKeyword)))
.ToArray();
var compilationUnit = CompilationUnit()
.AddMembers(classes);
// 只在最后格式化一次
return compilationUnit.NormalizeWhitespace().ToFullString();
}
// ❌ 不好:每次都格式化
public string GenerateMultipleClassesSlow(List<string> classNames)
{
var result = new StringBuilder();
foreach (var name in classNames)
{
var classDecl = ClassDeclaration(name)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.NormalizeWhitespace(); // 每次都格式化
result.AppendLine(classDecl.ToFullString());
}
return result.ToString();
}技巧 4: 使用 StringBuilder 拼接大量代码
// ✅ 好:对于简单的代码片段,使用 StringBuilder
public string GenerateManySimpleProperties(List<string> propertyNames)
{
var sb = new StringBuilder();
foreach (var name in propertyNames)
{
sb.AppendLine($"public string {name} {{ get; set; }}");
}
return sb.ToString();
}技巧 5: 缓存常用的语法节点
public class SyntaxNodeCache
{
// 缓存常用的类型
private static readonly PredefinedTypeSyntax StringType =
PredefinedType(Token(SyntaxKind.StringKeyword));
private static readonly PredefinedTypeSyntax IntType =
PredefinedType(Token(SyntaxKind.IntKeyword));
private static readonly PredefinedTypeSyntax BoolType =
PredefinedType(Token(SyntaxKind.BoolKeyword));
// 缓存常用的访问器
private static readonly AccessorDeclarationSyntax GetAccessor =
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
private static readonly AccessorDeclarationSyntax SetAccessor =
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
public PropertyDeclarationSyntax CreateStringProperty(string name)
{
return PropertyDeclaration(StringType, name)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(GetAccessor, SetAccessor);
}
}调试技巧
技巧 1: 使用 Syntax Visualizer
Roslyn 提供了 Syntax Visualizer 工具,可以帮助你理解语法树的结构。
安装方法:
- 在 Visual Studio 中,打开"扩展" > "管理扩展"
- 搜索 ".NET Compiler Platform SDK"
- 安装后,在"视图" > "其他窗口"中找到"Syntax Visualizer"
使用方法:
- 打开任何 C# 文件
- 在 Syntax Visualizer 中查看语法树结构
- 点击节点查看其类型和属性
- 复制节点的创建代码
技巧 2: 输出生成的代码进行检查
/// <summary>
/// 调试辅助方法:输出生成的代码
/// </summary>
public class CodeGenerationDebugger
{
public void DebugGeneratedCode(SyntaxNode node)
{
// 输出未格式化的代码
Console.WriteLine("=== 未格式化 ===");
Console.WriteLine(node.ToFullString());
Console.WriteLine();
// 输出格式化的代码
Console.WriteLine("=== 格式化后 ===");
Console.WriteLine(node.NormalizeWhitespace().ToFullString());
Console.WriteLine();
// 输出语法树结构
Console.WriteLine("=== 语法树结构 ===");
PrintSyntaxTree(node, 0);
}
private void PrintSyntaxTree(SyntaxNode node, int indent)
{
var indentStr = new string(' ', indent * 2);
Console.WriteLine($"{indentStr}{node.GetType().Name}: {node.Kind()}");
foreach (var child in node.ChildNodes())
{
PrintSyntaxTree(child, indent + 1);
}
}
}技巧 3: 验证生成的代码是否可编译
/// <summary>
/// 验证生成的代码是否可编译
/// </summary>
public class CodeValidator
{
public bool ValidateGeneratedCode(string code)
{
// 解析代码
var syntaxTree = CSharpSyntaxTree.ParseText(code);
// 检查语法错误
var diagnostics = syntaxTree.GetDiagnostics();
if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error))
{
Console.WriteLine("语法错误:");
foreach (var diagnostic in diagnostics)
{
Console.WriteLine($" {diagnostic.GetMessage()}");
}
return false;
}
// 创建编译
var compilation = CSharpCompilation.Create(
"ValidationAssembly",
new[] { syntaxTree },
new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location)
});
// 检查语义错误
var semanticDiagnostics = compilation.GetDiagnostics();
if (semanticDiagnostics.Any(d => d.Severity == DiagnosticSeverity.Error))
{
Console.WriteLine("语义错误:");
foreach (var diagnostic in semanticDiagnostics)
{
Console.WriteLine($" {diagnostic.GetMessage()}");
}
return false;
}
Console.WriteLine("代码验证通过!");
return true;
}
}技巧 4: 比较生成的代码和预期代码
/// <summary>
/// 比较生成的代码和预期代码
/// </summary>
public class CodeComparer
{
public bool CompareCode(string generated, string expected)
{
// 解析两段代码
var generatedTree = CSharpSyntaxTree.ParseText(generated);
var expectedTree = CSharpSyntaxTree.ParseText(expected);
// 格式化后比较
var generatedNormalized = generatedTree.GetRoot()
.NormalizeWhitespace()
.ToFullString();
var expectedNormalized = expectedTree.GetRoot()
.NormalizeWhitespace()
.ToFullString();
if (generatedNormalized == expectedNormalized)
{
Console.WriteLine("代码匹配!");
return true;
}
else
{
Console.WriteLine("代码不匹配!");
Console.WriteLine("=== 生成的代码 ===");
Console.WriteLine(generatedNormalized);
Console.WriteLine("=== 预期的代码 ===");
Console.WriteLine(expectedNormalized);
return false;
}
}
}技巧 5: 单元测试生成的代码
using Xunit;
/// <summary>
/// 代码生成单元测试示例
/// </summary>
public class CodeGenerationTests
{
[Fact]
public void GenerateClass_ShouldCreateValidClass()
{
// Arrange
var generator = new ClassBuilder();
// Act
var classDecl = generator
.WithName("Person")
.WithModifier("public")
.AddProperty("string", "Name")
.AddProperty("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);
// 验证代码可编译
var validator = new CodeValidator();
Assert.True(validator.ValidateGeneratedCode(code));
}
[Theory]
[InlineData("MyClass", "public class MyClass")]
[InlineData("Person", "public class Person")]
public void GenerateClass_WithDifferentNames_ShouldWork(
string className,
string expectedStart)
{
// Arrange & Act
var classDecl = ClassDeclaration(className)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.NormalizeWhitespace();
var code = classDecl.ToFullString();
// Assert
Assert.StartsWith(expectedStart, code);
}
}扩展阅读
推荐资源
官方文档
- Roslyn GitHub Repository
- SyntaxFactory API Documentation
- Roslyn Syntax Quoter - 在线工具,输入代码自动生成 SyntaxFactory 调用
相关指南
API 参考
实战示例
在线工具
Roslyn Quoter (http://roslynquoter.azurewebsites.net/)
- 输入 C# 代码,自动生成对应的 SyntaxFactory 调用
- 支持完整的 C# 语法
- 可以选择不同的输出格式
SharpLab (https://sharplab.io/)
- 在线 C# 编译器
- 可以查看语法树、IL 代码、JIT 汇编
- 支持最新的 C# 特性
Syntax Visualizer
- Visual Studio 扩展
- 实时查看代码的语法树结构
- 可以复制节点的创建代码
下一步学习
完成本文档的学习后,建议按以下顺序继续:
- 实践项目 - 创建一个简单的代码生成器
- 学习语义模型 - 了解如何分析代码的语义信息
- 掌握增量生成 - 学习如何优化生成器性能
- 阅读源码 - 研究 Roslyn 的源代码实现
社区资源
GitHub 讨论区
- Roslyn Discussions
- 提问和分享经验
Stack Overflow
- 标签:[roslyn], [source-generator], [csharp]
- 搜索常见问题的解决方案
博客文章
- Andrew Lock's Blog - 深入的源生成器文章
- .NET Blog - 官方博客
总结
代码生成 API 是 Roslyn 的核心功能之一,通过本文档,你应该掌握了:
- SyntaxFactory 基础 - 如何使用 SyntaxFactory 创建各种语法节点
- 代码构建模式 - 构建器模式和流式 API 的使用
- 格式化技巧 - 如何格式化和美化生成的代码
- 复杂结构生成 - 如何生成类、方法、属性、接口、枚举等
- 高级技术 - 泛型、特性、Lambda 表达式等高级特性的生成
- 真实场景 - DTO 生成器、Builder 模式生成器、API 客户端生成器
- 性能优化 - 如何提高代码生成的性能
- 调试技巧 - 如何调试和验证生成的代码
记住以下关键点:
- ✅ 使用
using static简化 SyntaxFactory 调用 - ✅ 始终使用
NormalizeWhitespace()格式化代码 - ✅ 使用构建器模式提高代码可维护性
- ✅ 缓存常用的语法节点和 token
- ✅ 批量添加成员而不是逐个添加
- ✅ 使用 Syntax Visualizer 学习语法树结构
- ✅ 编写单元测试验证生成的代码
- ❌ 不要忘记添加分号标记
- ❌ 不要在循环中重复格式化
- ❌ 不要硬编码字符串拼接复杂代码
继续学习相关主题,深入掌握 Roslyn 的强大功能!
本文档最后更新: 2025-01-21文档版本: 2.0贡献者: Roslyn 文档团队
代码生成最佳实践详解
实践 1: 分层代码生成架构
在大型项目中,建议采用分层架构来组织代码生成逻辑:
/// <summary>
/// 分层代码生成架构示例
/// </summary>
public class LayeredCodeGeneration
{
// 第一层:数据模型层
public class CodeModel
{
public string ClassName { get; set; }
public List<PropertyModel> Properties { get; set; }
public List<MethodModel> Methods { get; set; }
}
public class PropertyModel
{
public string Name { get; set; }
public string Type { get; set; }
public bool IsReadOnly { get; set; }
public string Documentation { get; set; }
}
public class MethodModel
{
public string Name { get; set; }
public string ReturnType { get; set; }
public List<ParameterModel> Parameters { get; set; }
public string Body { get; set; }
}
public class ParameterModel
{
public string Name { get; set; }
public string Type { get; set; }
}
// 第二层:语法生成层
public class SyntaxGenerator
{
public ClassDeclarationSyntax GenerateClass(CodeModel model)
{
var classDecl = ClassDeclaration(model.ClassName)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 生成属性
var properties = model.Properties
.Select(p => GenerateProperty(p))
.ToArray();
// 生成方法
var methods = model.Methods
.Select(m => GenerateMethod(m))
.ToArray();
return classDecl
.AddMembers(properties)
.AddMembers(methods);
}
private PropertyDeclarationSyntax GenerateProperty(PropertyModel model)
{
var property = PropertyDeclaration(
ParseTypeName(model.Type),
Identifier(model.Name))
.AddModifiers(Token(SyntaxKind.PublicKeyword));
if (model.IsReadOnly)
{
property = property.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
}
else
{
property = property.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
}
return property;
}
private MethodDeclarationSyntax GenerateMethod(MethodModel model)
{
var method = MethodDeclaration(
ParseTypeName(model.ReturnType),
Identifier(model.Name))
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 添加参数
if (model.Parameters != null && model.Parameters.Any())
{
var parameters = model.Parameters
.Select(p => Parameter(Identifier(p.Name))
.WithType(ParseTypeName(p.Type)))
.ToArray();
method = method.AddParameterListParameters(parameters);
}
// 添加方法体
if (!string.IsNullOrEmpty(model.Body))
{
var statements = ParseStatement(model.Body);
method = method.WithBody(Block(statements));
}
else
{
method = method.WithBody(Block());
}
return method;
}
}
// 第三层:代码格式化层
public class CodeFormatter
{
public string Format(SyntaxNode node)
{
// 格式化代码
var formatted = node.NormalizeWhitespace();
// 添加文件头注释
var header = Comment(@"//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: " + Environment.Version + @"
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------");
formatted = formatted.WithLeadingTrivia(
TriviaList(header, CarriageReturnLineFeed, CarriageReturnLineFeed));
return formatted.ToFullString();
}
}
// 第四层:代码输出层
public class CodeWriter
{
public void WriteToFile(string code, string filePath)
{
// 确保目录存在
var directory = Path.GetDirectoryName(filePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
// 写入文件
File.WriteAllText(filePath, code, Encoding.UTF8);
}
public void WriteToContext(string code, SourceProductionContext context, string fileName)
{
// 在源生成器中使用
context.AddSource(fileName, code);
}
}
}实践 2: 模板化代码生成
使用模板方法模式来标准化代码生成流程:
/// <summary>
/// 模板化代码生成基类
/// </summary>
public abstract class CodeGeneratorTemplate
{
/// <summary>
/// 模板方法:定义代码生成的标准流程
/// </summary>
public string Generate()
{
// 1. 准备数据
var model = PrepareModel();
// 2. 验证模型
ValidateModel(model);
// 3. 生成语法树
var syntaxNode = GenerateSyntax(model);
// 4. 后处理
syntaxNode = PostProcess(syntaxNode);
// 5. 格式化
var formatted = FormatCode(syntaxNode);
// 6. 验证生成的代码
ValidateGeneratedCode(formatted);
return formatted;
}
/// <summary>
/// 准备数据模型(子类实现)
/// </summary>
protected abstract object PrepareModel();
/// <summary>
/// 验证模型(可选覆盖)
/// </summary>
protected virtual void ValidateModel(object model)
{
if (model == null)
{
throw new ArgumentNullException(nameof(model));
}
}
/// <summary>
/// 生成语法树(子类实现)
/// </summary>
protected abstract SyntaxNode GenerateSyntax(object model);
/// <summary>
/// 后处理(可选覆盖)
/// </summary>
protected virtual SyntaxNode PostProcess(SyntaxNode node)
{
return node;
}
/// <summary>
/// 格式化代码(可选覆盖)
/// </summary>
protected virtual string FormatCode(SyntaxNode node)
{
return node.NormalizeWhitespace().ToFullString();
}
/// <summary>
/// 验证生成的代码(可选覆盖)
/// </summary>
protected virtual void ValidateGeneratedCode(string code)
{
if (string.IsNullOrWhiteSpace(code))
{
throw new InvalidOperationException("生成的代码为空");
}
}
}
/// <summary>
/// 具体的代码生成器实现
/// </summary>
public class EntityGenerator : CodeGeneratorTemplate
{
private readonly string _entityName;
private readonly List<string> _properties;
public EntityGenerator(string entityName, List<string> properties)
{
_entityName = entityName;
_properties = properties;
}
protected override object PrepareModel()
{
return new
{
EntityName = _entityName,
Properties = _properties
};
}
protected override SyntaxNode GenerateSyntax(object model)
{
dynamic m = model;
var classDecl = ClassDeclaration(m.EntityName)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
foreach (string prop in m.Properties)
{
var property = PropertyDeclaration(
PredefinedType(Token(SyntaxKind.StringKeyword)),
prop)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.AddAccessorListAccessors(
AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)),
AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Token(SyntaxKind.SemicolonToken)));
classDecl = classDecl.AddMembers(property);
}
return classDecl;
}
protected override SyntaxNode PostProcess(SyntaxNode node)
{
// 添加 XML 文档注释
return node.WithLeadingTrivia(
TriviaList(
Comment("/// <summary>"),
CarriageReturnLineFeed,
Comment($"/// {_entityName} 实体类"),
CarriageReturnLineFeed,
Comment("/// </summary>"),
CarriageReturnLineFeed));
}
}实践 3: 错误处理和日志记录
在代码生成过程中,完善的错误处理和日志记录至关重要:
/// <summary>
/// 带错误处理和日志的代码生成器
/// </summary>
public class RobustCodeGenerator
{
private readonly ILogger _logger;
public RobustCodeGenerator(ILogger logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public Result<string> GenerateCode(CodeModel model)
{
try
{
_logger.LogInformation($"开始生成代码: {model.ClassName}");
// 验证输入
var validationResult = ValidateModel(model);
if (!validationResult.IsSuccess)
{
_logger.LogError($"模型验证失败: {validationResult.Error}");
return Result<string>.Failure(validationResult.Error);
}
// 生成代码
var syntaxNode = GenerateSyntax(model);
_logger.LogDebug("语法树生成完成");
// 格式化
var code = syntaxNode.NormalizeWhitespace().ToFullString();
_logger.LogDebug($"代码格式化完成,长度: {code.Length}");
// 验证生成的代码
var codeValidation = ValidateGeneratedCode(code);
if (!codeValidation.IsSuccess)
{
_logger.LogError($"生成的代码验证失败: {codeValidation.Error}");
return Result<string>.Failure(codeValidation.Error);
}
_logger.LogInformation($"代码生成成功: {model.ClassName}");
return Result<string>.Success(code);
}
catch (Exception ex)
{
_logger.LogError(ex, $"代码生成过程中发生异常: {model.ClassName}");
return Result<string>.Failure($"代码生成失败: {ex.Message}");
}
}
private Result ValidateModel(CodeModel model)
{
if (model == null)
return Result.Failure("模型不能为空");
if (string.IsNullOrWhiteSpace(model.ClassName))
return Result.Failure("类名不能为空");
if (!IsValidIdentifier(model.ClassName))
return Result.Failure($"类名 '{model.ClassName}' 不是有效的标识符");
return Result.Success();
}
private bool IsValidIdentifier(string name)
{
if (string.IsNullOrEmpty(name))
return false;
if (!char.IsLetter(name[0]) && name[0] != '_')
return false;
return name.All(c => char.IsLetterOrDigit(c) || c == '_');
}
private ClassDeclarationSyntax GenerateSyntax(CodeModel model)
{
// 实现代码生成逻辑
return ClassDeclaration(model.ClassName)
.AddModifiers(Token(SyntaxKind.PublicKeyword));
}
private Result ValidateGeneratedCode(string code)
{
if (string.IsNullOrWhiteSpace(code))
return Result.Failure("生成的代码为空");
// 尝试解析代码
var syntaxTree = CSharpSyntaxTree.ParseText(code);
var diagnostics = syntaxTree.GetDiagnostics();
var errors = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToList();
if (errors.Any())
{
var errorMessages = string.Join("; ", errors.Select(e => e.GetMessage()));
return Result.Failure($"生成的代码包含语法错误: {errorMessages}");
}
return Result.Success();
}
}
/// <summary>
/// 结果类型
/// </summary>
public class Result
{
public bool IsSuccess { get; protected set; }
public string Error { get; protected set; }
public static Result Success() => new Result { IsSuccess = true };
public static Result Failure(string error) => new Result { IsSuccess = false, Error = error };
}
public class Result<T> : Result
{
public T Value { get; private set; }
public static Result<T> Success(T value) => new Result<T> { IsSuccess = true, Value = value };
public new static Result<T> Failure(string error) => new Result<T> { IsSuccess = false, Error = error };
}
/// <summary>
/// 简单的日志接口
/// </summary>
public interface ILogger
{
void LogInformation(string message);
void LogDebug(string message);
void LogError(string message);
void LogError(Exception ex, string message);
}这些最佳实践可以帮助你构建更加健壮、可维护和高效的代码生成系统。记住,良好的架构设计和错误处理是成功的关键!