详解C#中有趣的 SourceGenerator生成器
一:背景
1. 讲故事
前些天在看 AOT的时候关注了下 源生成器
,挺有意思的一个东西,今天写一篇文章简单的分享下。
二:源生成器探究之旅
1. 源生成器是什么
简单来说,源生成器是Roslyn编译器
给程序员开的一道口子,在这个口子里可以塞入一些自定义的cs代码,让Roslyn编译器
在编译代码的时候顺带给一起处理了,简单的说就是 夹带私货 ,但古话又说 师不顺路, 医不叩门
,所以还是比较尴尬的,看一下官方给的图,图中的橙色区域就是夹带的私货。
有些朋友肯定好奇,这玩意有什么用?其实在AOT领域中,JsonSerializer 就使用了 SourceGeneration
来给序列化的类型(WeatherForecast)生成元数据,参考代码如下:
[JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(WeatherForecast))] internal partial class SourceGenerationContext : JsonSerializerContext { }
2. 一个简单的例子
上面的例子不过多深入,先看看怎么实现0到1的问题,这里使用官方例子,用钩子来实现 分布方法
的方法体。
新建 SourceGenerator 类库项目
这里面的source就是钩子代码,不过目前只能是.NET Standard 2.0
项目,应该是要达到最大的兼容性,参考代码如下:
namespace SourceGenerator { [Generator] public class HelloSourceGenerator : ISourceGenerator { public void Execute(GeneratorExecutionContext context) { // Find the main method var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken); // Build up the source code string source = $@" // <auto-generated/> using System; namespace {mainMethod.ContainingNamespace.ToDisplayString()} {{ public static partial class {mainMethod.ContainingType.Name} {{ static partial void HelloFrom(string name) => Console.WriteLine($""Generator says: Hi from '{{name}}'""); }} }} "; var typeName = mainMethod.ContainingType.Name; // Add the source code to the compilation context.AddSource($"{typeName}.g.cs", source); } public void Initialize(GeneratorInitializationContext context) { // No initialization required for this one } } }
新建 Example_21_15 项目
这是一个控制台程序,引用刚才的项目,并声明部分方法 HelloFrom
,参考代码如下:
namespace Example_21_15 { partial class Program { static void Main(string[] args) { HelloFrom("Generated Code"); Console.ReadLine(); } static partial void HelloFrom(string name); } }
要记住在 Example_21_15.csproj 中 Include 时要额外增加两个参数,参考如下:
<ItemGroup> <ProjectReference Include="..\SourceGenerator\SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> </ItemGroup>
配置好之后就可以把程序跑起来了,可以看到方法体确实是钩子中的代码。
三:Roslyn如何夹带私货
1. windbg调试
究竟是如何夹带私货,本质上是 Roslyn 内部的逻辑,现在的问题是如何给他挖出来了呢?这就需要使用强大的 windbg,采用exe启动劫持的方式洞察,流程步骤如下:
windbg 的exe劫持
资深的 WinDbg 玩家我相信都知道这个招数,我写了一个简单的 bat 脚本,对 dotnet.exe 进行启动拦截,要提醒的是有安全软件的话可以先卸载掉,以免出现无权限的问题。
SET ApplicationName=dotnet.exe SET WinDbgPath=C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\windbg.exe REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\%ApplicationName%" /v debugger /t REG_SZ /d "%WinDbgPath%" /f ECHO 已成功设置 PAUSE
您可能感兴趣的文章
- 11-29C# 中的委托与事件机制详解
- 11-29C#中基数排序算法的原理及实现
- 11-29C#中计数排序算法的原理及实现
- 11-29C#实现线性搜索算法
- 11-29C#实现希尔排序算法的实践
- 11-29C#实现桶排序算法的示例代码
- 11-29C#实现广度优先搜索的实例代码
- 11-29C#中实现深度优先搜索
- 11-29C# 变量作用域常用说明小结
- 11-29详解C#中有趣的 SourceGenerator生成器


阅读排行
推荐教程
- 11-29C#解决Excel边框样式无法复制及格式刷功能
- 11-29C#自定义控件指示灯效果
- 11-29C#中计数排序算法的原理及实现
- 11-29C#实现线性搜索算法
- 11-29C#删除Word文档中的段落的方法示例
- 11-29C#中基数排序算法的原理及实现
- 11-29C# System.Linq提供类似SQL语法的高效查询操作
- 11-29C# WPF中实现图表生成的五种方式
- 11-29C#利用ms office实现office转pdf的示例代码
- 11-29C#实现身份证实名认证接口的示例代码