Skip to content

第 3 步:Hello World

加载进度中...

📋 本步目标

完成本步后,你将能够:

  • 创建第一个源生成器项目
  • 编写简单的代码生成逻辑
  • 查看和理解生成的代码
  • 在消费者项目中使用生成的代码

⏱️ 预计时间

约 45 分钟


📚 学习内容

1. 创建生成器项目

步骤 1:创建项目结构

bash
# 创建解决方案目录
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

xml
<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,添加对生成器的引用:

xml
<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

csharp
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 接口

  • 必须实现的接口
  • 定义了 InitializeExecute 两个方法

Initialize 方法

  • 初始化生成器(可选)
  • 可以注册语法接收器等
  • 本示例中为空

Execute 方法

  • 执行代码生成的核心逻辑
  • 在每次编译时都会被调用
  • 通过 context.AddSource 添加生成的代码

AddSource 方法

  • 将生成的代码添加到编译中
  • 第一个参数:文件名(必须唯一,建议以 .g.cs 结尾)
  • 第二个参数:源代码字符串

生成的代码在哪里?

生成的代码不会出现在项目文件夹中,而是在 obj/Debug/net8.0/generated/ 目录下。这些文件是临时的,每次编译都会重新生成。

3. 使用生成的代码

编辑 HelloWorld.Consumer/Program.cs

csharp
using System;
using Generated;

class Program
{
    static void Main()
    {
        // 调用生成器生成的方法
        Console.WriteLine(HelloWorld.SayHello());
        // 输出: Hello from Source Generator!
    }
}

4. 构建和运行

bash
# 构建项目
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 中:

  1. 展开 Dependencies → Analyzers → HelloWorld.Generator
  2. 或者在 Solution Explorer 中启用"显示所有文件"
Q: 生成器没有运行怎么办?

A: 检查:

  1. 生成器项目是否使用 netstandard2.0
  2. 消费者项目的引用配置是否正确
  3. 尝试清理并重新构建:dotnet clean && dotnet build
Q: 如何调试生成器?

A: 在生成器代码中添加:

csharp
System.Diagnostics.Debugger.Launch();

然后重新构建,会弹出调试器选择对话框。


⏭️ 下一步

恭喜!你已经创建了第一个源生成器。下一步我们将学习如何创建更实用的 ToString 生成器。

基于 MIT 许可发布