格式化和美化
📋 文档信息
难度: 🟢 简单
预计阅读时间: 15 分钟
前置知识:
- SyntaxFactory 基础
- C# 基础语法
适合人群:
- 所有代码生成器开发者
- 需要生成格式化代码的开发者
📋 快速导航
| 章节 | 难度 | 阅读时间 | 链接 |
|---|---|---|---|
| NormalizeWhitespace | 🟢 | 5 分钟 | 查看 |
| 自定义格式化 | 🟡 | 7 分钟 | 查看 |
| 完整示例 | 🟡 | 3 分钟 | 查看 |
🎯 概览
本文档介绍如何格式化和美化生成的代码,使其具有良好的可读性和一致的风格。
本文档涵盖:
- 使用 NormalizeWhitespace 自动格式化
- 自定义缩进和换行
- 添加 XML 文档注释
- 添加区域标记
典型应用场景:
- 生成格式化良好的代码
- 添加文档注释
- 组织代码结构
NormalizeWhitespace
NormalizeWhitespace 方法是格式化生成代码的最简单方式。
基本格式化
csharp
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; }
// }
}
}自定义缩进
csharp
/// <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();
}格式化整个编译单元
csharp
/// <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; }
// }
// }
}自定义格式化
添加 XML 文档注释
csharp
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 PropertyDeclarationSyntax AddPropertyDocumentation(
PropertyDeclarationSyntax property,
string summary)
{
return property.WithLeadingTrivia(
TriviaList(
CarriageReturnLineFeed,
Whitespace(" "),
Comment("/// <summary>"),
CarriageReturnLineFeed,
Whitespace(" "),
Comment($"/// {summary}"),
CarriageReturnLineFeed,
Whitespace(" "),
Comment("/// </summary>"),
CarriageReturnLineFeed,
Whitespace(" ")));
}
}添加区域标记
csharp
/// <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;
}格式化完整示例
csharp
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;
}
}💡 最佳实践
实践 1: 始终格式化生成的代码
csharp
// ✅ 好:格式化代码
public string GenerateCode()
{
var classDecl = ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 格式化
var formatted = classDecl.NormalizeWhitespace();
return formatted.ToFullString();
}
// ❌ 差:不格式化
public string GenerateCode()
{
var classDecl = ClassDeclaration("MyClass")
.AddModifiers(Token(SyntaxKind.PublicKeyword));
// 直接返回,没有格式化
return classDecl.ToFullString();
// 结果:public class MyClass{} // 没有换行和缩进
}原因: 格式化的代码更易读,更符合编码规范。
实践 2: 添加有意义的文档注释
csharp
// ✅ 好:添加文档注释
var classDecl = ClassDeclaration("Person")
.WithLeadingTrivia(
TriviaList(
Comment("/// <summary>"),
CarriageReturnLineFeed,
Comment("/// 表示一个人的信息"),
CarriageReturnLineFeed,
Comment("/// </summary>"),
CarriageReturnLineFeed));
// ❌ 差:没有文档注释
var classDecl = ClassDeclaration("Person");原因: 文档注释提高代码的可维护性和可读性。
实践 3: 使用一致的缩进
csharp
// ✅ 好:使用一致的缩进
var formatted = classDecl.NormalizeWhitespace(indentation: " ");
// ❌ 差:混合使用不同的缩进
// 有些地方用 2 个空格,有些地方用 4 个空格原因: 一致的缩进使代码更整洁,更易读。
⚠️ 常见错误
错误 1: 忘记格式化代码
问题: 生成的代码没有格式化,难以阅读。
csharp
// ❌ 错误:没有格式化
var code = classDecl.ToFullString();
// 结果:public class MyClass{public string Name{get;set;}}解决方案:
csharp
// ✅ 正确:使用 NormalizeWhitespace
var code = classDecl.NormalizeWhitespace().ToFullString();
// 结果:格式化的代码错误 2: 文档注释格式不正确
问题: XML 文档注释的格式不正确,导致 IDE 无法识别。
csharp
// ❌ 错误:注释格式不正确
var classDecl = ClassDeclaration("MyClass")
.WithLeadingTrivia(
TriviaList(Comment("// This is my class"))); // 使用普通注释解决方案:
csharp
// ✅ 正确:使用 XML 文档注释
var classDecl = ClassDeclaration("MyClass")
.WithLeadingTrivia(
TriviaList(
Comment("/// <summary>"),
CarriageReturnLineFeed,
Comment("/// This is my class"),
CarriageReturnLineFeed,
Comment("/// </summary>"),
CarriageReturnLineFeed));错误 3: 缩进不一致
问题: 生成的代码缩进不一致。
csharp
// ❌ 错误:手动添加缩进,容易出错
var code = "public class MyClass\n{\n public string Name { get; set; }\n}";解决方案:
csharp
// ✅ 正确:使用 NormalizeWhitespace 自动处理缩进
var formatted = classDecl.NormalizeWhitespace();
var code = formatted.ToFullString();🔗 相关文档
- 返回索引
- SyntaxFactory 基础 - 学习 SyntaxFactory 的基本使用
- SyntaxFactory 高级 - 学习复杂结构的生成技术
- 代码构建模式 - 学习常用的代码构建模式
- 最佳实践 - 掌握代码生成的最佳实践
其他相关文档
📚 下一步
学习完本文档后,建议继续学习:
最后更新: 2026-02-05
文档版本: 1.0