第 3 步:Hello World
加载进度中...
📋 本步目标
完成本步后,你将能够:
- 创建第一个源生成器项目
- 编写简单的代码生成逻辑
- 查看和理解生成的代码
- 在消费者项目中使用生成的代码
⏱️ 预计时间
约 45 分钟
📚 学习内容
1. 创建生成器项目
步骤 1:创建项目结构
# 创建解决方案目录
mkdir HelloWorldGenerator
cd HelloWorldGenerator
# 创建解决方案
dotnet new sln -n HelloWorldGenerator
# 创建生成器项目(类库)
dotnet new classlib -n HelloWorld.Generator
# 创建消费者项目(控制台)
dotnet new console -n HelloWorld.Consumer
# 添加到解决方案
dotnet sln add HelloWorld.Generator/HelloWorld.Generator.csproj
dotnet sln add HelloWorld.Consumer/HelloWorld.Consumer.csproj步骤 2:配置生成器项目
编辑 HelloWorld.Generator/HelloWorld.Generator.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
</ItemGroup>
</Project>配置说明
TargetFramework: netstandard2.0
- 源生成器必须使用 netstandard2.0
- 这是编译器(Roslyn)支持的标准
- 即使你的应用是 .NET 8,生成器也必须是 netstandard2.0
LangVersion: latest
- 允许使用最新的 C# 语言特性
- 虽然目标是 netstandard2.0,但可以使用新语法
PrivateAssets="all"
- 防止 Roslyn 依赖传递给使用者项目
- 避免使用者项目引入不必要的大型依赖(100+ MB)
步骤 3:配置消费者项目
编辑 HelloWorld.Consumer/HelloWorld.Consumer.csproj,添加对生成器的引用:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\HelloWorld.Generator\HelloWorld.Generator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>重要配置
OutputItemType="Analyzer"
- 告诉编译器这是一个分析器/生成器
- 编译器会在编译时加载并运行它
- 不是普通的程序集引用
ReferenceOutputAssembly="false"
- 不引用生成器的 DLL
- 生成器只在编译时运行,运行时不需要
- 减少最终应用程序的大小
2. 编写第一个生成器
创建 HelloWorld.Generator/HelloWorldGenerator.cs:
using Microsoft.CodeAnalysis;
namespace HelloWorld.Generator
{
[Generator]
public class HelloWorldGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
// 初始化代码(本示例中为空)
}
public void Execute(GeneratorExecutionContext context)
{
// 生成的源代码
var sourceCode = @"
namespace Generated
{
public static class HelloWorld
{
public static string SayHello() => ""Hello from Source Generator!"";
}
}";
// 添加源文件到编译
context.AddSource("HelloWorld.g.cs", sourceCode);
}
}
}代码解析
[Generator] 特性
- 标记类为源生成器
- Roslyn 通过反射查找带有此特性的类
- 没有这个特性,生成器不会被发现和执行
ISourceGenerator 接口
- 必须实现的接口
- 定义了
Initialize和Execute两个方法
Initialize 方法
- 初始化生成器(可选)
- 可以注册语法接收器等
- 本示例中为空
Execute 方法
- 执行代码生成的核心逻辑
- 在每次编译时都会被调用
- 通过
context.AddSource添加生成的代码
AddSource 方法
- 将生成的代码添加到编译中
- 第一个参数:文件名(必须唯一,建议以
.g.cs结尾) - 第二个参数:源代码字符串
生成的代码在哪里?
生成的代码不会出现在项目文件夹中,而是在 obj/Debug/net8.0/generated/ 目录下。这些文件是临时的,每次编译都会重新生成。
3. 使用生成的代码
编辑 HelloWorld.Consumer/Program.cs:
using System;
using Generated;
class Program
{
static void Main()
{
// 调用生成器生成的方法
Console.WriteLine(HelloWorld.SayHello());
// 输出: Hello from Source Generator!
}
}4. 构建和运行
# 构建项目
dotnet build
# 运行消费者项目
dotnet run --project HelloWorld.Consumer你应该看到输出:
Hello from Source Generator!5. 查看生成的代码
生成的代码位于:
HelloWorld.Consumer/obj/Debug/net8.0/generated/
└── HelloWorld.Generator/
└── HelloWorld.Generator.HelloWorldGenerator/
└── HelloWorld.g.cs在 Visual Studio 中,你可以在 Solution Explorer 中展开 Dependencies → Analyzers → HelloWorld.Generator 查看生成的文件。
📚 相关 API
本步骤使用了以下 API:
ISourceGenerator
传统的源生成器接口,提供 Initialize 和 Execute 方法。
GeneratorExecutionContext
提供代码生成的上下文,包含 AddSource 等方法。
AddSource()
将生成的代码添加到编译中的核心方法。
💡 下一步学习
完成本步骤后,建议:
✅ 检查点
✅ 检查点
完成以下任务后,可以进入下一步:
💡 常见问题
Q: 为什么看不到生成的代码?
A: 生成的代码在 obj/ 目录下。在 Visual Studio 中:
- 展开 Dependencies → Analyzers → HelloWorld.Generator
- 或者在 Solution Explorer 中启用"显示所有文件"
Q: 生成器没有运行怎么办?
A: 检查:
- 生成器项目是否使用 netstandard2.0
- 消费者项目的引用配置是否正确
- 尝试清理并重新构建:
dotnet clean && dotnet build
Q: 如何调试生成器?
A: 在生成器代码中添加:
System.Diagnostics.Debugger.Launch();然后重新构建,会弹出调试器选择对话框。
⏭️ 下一步
恭喜!你已经创建了第一个源生成器。下一步我们将学习如何创建更实用的 ToString 生成器。