你是否曾经为了重复的代码模板而感到厌烦?是否想过让编译器帮你自动生成代码?今天我要分享一个C#开发中的"黑科技"——源生成器(Source Generator)。这项技术可以在编译时自动生成代码,不仅能提升开发效率,还能减少运行时反射的性能开销。本文将通过一个完整的实战案例,带你掌握这项强大的技术。
在日常C#开发中,我们经常遇到这些痛点:
重复代码问题:比如属性通知、序列化代码、API接口包装等,大量模板化代码需要手写。
运行时反射开销:传统的代码生成依赖反射,会带来性能损耗。
编译时安全性:动态生成的代码缺乏编译时检查,容易出现运行时错误。
代码维护困难:手写的模板代码增加了维护成本。
源生成器完美解决了这些问题,它在编译时分析你的代码,然后自动生成需要的代码片段,既保证了性能,又提供了编译时安全性。
源生成器基于Roslyn编译器平台,工作流程如下:
这种机制的最大优势是零运行时开销,生成的代码就像手写代码一样高效。
让我们通过实际代码来理解源生成器的工作原理。
首先创建两个项目:
生成器项目(AppSourceGeneratorLibrary.csproj)
XML<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all" />
</ItemGroup>
</Project>
关键配置说明:
netstandard2.0
:确保兼容性(必须的)IncludeBuildOutput>false
:不将生成器dll包含到输出中PrivateAssets="all"
:避免传递依赖使用项目(AppSourceGenerator.csproj)
XML<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AppSourceGeneratorLibrary\AppSourceGeneratorLibrary.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
核心配置:
OutputItemType="Analyzer"
:将项目作为分析器引用ReferenceOutputAssembly="false"
:不引用生成器的程序集C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis;
#pragma warning disable RS1035
namespace AppSourceGeneratorLibrary
{
[Generator]
public class HelloWorldGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
// 🔥 代码生成的核心逻辑
StringBuilder sourceBuilder = new StringBuilder(@"
using System;
namespace HelloWorldGenerated
{
public static class HelloWorld
{
public static void SayHello()
{
Console.WriteLine(""Hello 代码生成了"");
");
// 📊 分析编译中的所有语法树
IEnumerable<SyntaxTree> syntaxTrees = context.Compilation.SyntaxTrees;
// 🔄 动态添加文件路径信息
foreach (SyntaxTree tree in syntaxTrees)
{
sourceBuilder.AppendLine($@"Console.WriteLine(@"" - {tree.FilePath}"");");
}
sourceBuilder.Append(@"
}
}
}");
// ✨ 将生成的代码注入到编译过程
context.AddSource("helloWorldGenerated.g.cs",
SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
public void Initialize(GeneratorInitializationContext context)
{
// 这里可以注册语法接收器等高级功能
}
}
}
C#using HelloWorldGenerated;
namespace AppSourceGenerator
{
class Program
{
static void Main()
{
HelloWorld.SayHello(); // 调用生成器创建的方法
}
}
}
源生成器在实际项目中有广泛应用:
1. 属性通知生成:自动为ViewModels生成INotifyPropertyChanged实现
2. 序列化代码:为类自动生成JSON序列化代码
3. 映射代码:自动生成对象映射逻辑
4. API客户端:根据OpenAPI规范自动生成HTTP客户端
5. 配置绑定:自动生成强类型配置类
性能陷阱:
StringBuilder
而非字符串拼接来构建代码调试困难:
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
来查看System.Diagnostics.Debugger.Launch()
来调试生成器版本兼容性:
语法接收器使用:
C#public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new CustomSyntaxReceiver());
}
增量生成:利用IIncrementalGenerator
接口提升大型项目的编译性能。
属性标记:结合特性来控制代码生成逻辑,实现更精确的控制。
源生成器是现代C#开发的重要工具,它通过编译时代码生成解决了传统反射的性能问题。掌握这项技术,你可以:
✅ 提升开发效率:自动化重复代码的编写
✅ 优化运行性能:消除反射带来的运行时开销
✅ 增强代码质量:提供编译时安全检查
随着.NET生态的发展,源生成器将在更多场景中发挥重要作用。建议你在项目中逐步引入这项技术,从简单场景开始,逐步扩展到复杂应用。
💬 互动话题:你在项目中遇到过哪些重复代码的场景?是否考虑过用源生成器来解决?欢迎在评论区分享你的经验和想法!
觉得这篇文章对你有帮助吗?请转发给更多需要的C#开发同行! 🚀
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!