Source Generator:C# 9将迎来编译时元编程

2020 年 5 月 20 日

Source Generator:C# 9将迎来编译时元编程

源码生成器(Source Generator)是C#编译器的一个新特性,开发者可以使用编译器生成的元数据检查用户代码,并生成附加的源文件,与程序的其他部分一起编译。

F#类型提供程序的启发,C#源码生成器的目标也是为了启用元编程,只是以一种完全不同的方式。实际上,F#类型提供程序在内存中触发类型、属性和方法,而源码生成器是将 C#代码重新加入编译过程。

源码生成器不能修改已有代码,只能向编译添加新代码。源码生成器的另一个限制是它不对其他源码生成器生成的代码起作用。这样可以确保每个代码生成器将看到相同的编译输入,而不管应用程序的顺序是怎样的。有趣的是,源码生成器并不局限于检查源代码及其相关的元数据,它们还可以访问其他文件。

具体来说,源码生成器并不是代码重写工具,比如优化器或代码注入器,也不是用来创建新的语言特性的,尽管这在技术上来说是可行的。源码生成器的使用场景包括自动接口实现、数据序列化,等等。在源码生成器指南中可以找到更多应用场景,其中还包含了讨论内容。

源码生成器与Roslyn 代码分析器有很大的关系,这从它的接口定义可以很明显地看出来:

复制代码
namespace Microsoft.CodeAnalysis
{
public interface ISourceGenerator
{
void Initialize(InitializationContext context);
void Execute(SourceGeneratorContext context);
}
}

编译器调用 Initialize 方法,生成器注册一些稍后将会调用的回调函数。代码生成发生在 Execute 方法里,它的参数是一个 SourceGeneratorContext 对象,该对象提供对当前 Compilation 对象的访问。

复制代码
namespace Microsoft.CodeAnalysis
{
public readonly struct SourceGeneratorContext
{
public ImmutableArray<AdditionalText> AdditionalFiles { get; }
public CancellationToken CancellationToken { get; }
public Compilation Compilation { get; }
public ISyntaxReceiver? SyntaxReceiver { get; }
public void ReportDiagnostic(Diagnostic diagnostic) { throw new NotImplementedException(); }
public void AddSource(string fileNameHint, SourceText sourceText) { throw new NotImplementedException(); }
}
}

可以修改 SourceGeneratorContext 对象,使用 AddSource 来包含其他代码。正如上面提到的,源码生成器不仅限于 C#文件。这从 AdditionalFiles 就可以看出来,它支持传给编译器的任意文件。

综上所述,要为“hello world”程序定义一个普通的源码生成器可以这样:

复制代码
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace SourceGeneratorSamples
{
[Generator]
public class HelloWorldGenerator : ISourceGenerator
{
public void Execute(SourceGeneratorContext context)
{
// begin creating the source we'll inject into the users compilation
var sourceBuilder = new StringBuilder(@"
using System;
namespace HelloWorldGenerated
{
public static class HelloWorld
{
public static void SayHello()
{
Console.WriteLine(""Hello from generated code!"");
Console.WriteLine(""The following syntax trees existed in the compilation that created this program:"");
");
// using the context, get a list of syntax trees in the users compilation
var syntaxTrees = context.Compilation.SyntaxTrees;
// add the filepath of each tree to the class we're building
foreach (SyntaxTree tree in syntaxTrees)
{
sourceBuilder.AppendLine($@"Console.WriteLine(@"" - {tree.FilePath}"");");
}
// finish creating the source to inject
sourceBuilder.Append(@"
}
}
}");
// inject the created source into the users compilation
context.AddSource("helloWorldGenerator", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
public void Initialize(InitializationContext context)
{
// No initialization required for this one
}
}
}

微软已经发布了更多的介绍性示例,向开发人员展示如何使用这个新特性。

源代码生成器可在.NET 5 预览版和最新的 Visual Studio 预览版中使用。这个特性仍然处于早期阶段,它的 API 和特性可能会在将来的版本中发生变化。

原文链接

Source Generators Will Enable Compile-Time Metaprogramming in C# 9

2020 年 5 月 20 日 09:00 1092

评论 1 条评论

发布
用户头像
感觉类似于“动态编译”
2020 年 05 月 22 日 11:34
回复
没有更多评论了
发现更多内容

腾讯面试题: 百度搜索为什么那么快?

小松漫步

面试

阿里巴巴大规模应用 Flink 的实战经验:常见问题诊断思路

Apache Flink

flink

干货分享丨玩转物联网IoTDA服务系列四-智能网关

华为云开发者社区

物联网 智能设备 应用场景 华为云 mqtt

LeetCode题解:1. 两数之和,JavaScript,双循环暴力解法,详细注释

Lee Chen

LeetCode 前端进阶训练营

第7周作业

文古

2. 妈呀,Jackson原来是这样写JSON的

YourBatman

Java json Jackson Fastjson

敏捷软件开发宣言及十二原则

Young先生

敏捷开发

Nginx 限流配置

Bruce Duan

Nginx限流

高能预警!Apache Flink Meetup · 上海站返场啦

Apache Flink

flink

架构师那些不能碰的禁忌

曲水流觞TechRill

架构师

架构师训练营第八周学习总结

张明森

脑洞:基于Enterprise Continuum证明DDD用于构建汽车的可行性

Winfield

企业架构 领域驱动设计 DDD 架构演进

Demo 示例:如何原生的在 K8s 上运行 Flink?

Apache Flink

flink

Vue 学习笔记-3

多选参数

vue.js Vue vuejs

主宰操作系统的经典算法

cxuan

后端 操作系统

Linux服务器存在某进程CPU过高如何追溯其问题根源?

Nick

Java centos #linux

节约60%成本!虎牙直播云端大数据是怎么做到的?

小小的一朵云

如何识别刷屏文章中的伪科学

Lee Chen

随笔杂谈 前端进阶训练营

关于中台,可能都是正确的废话

fino星君

中台 业务中台

Vue 学习笔记-2

多选参数

vue.js Vue vuejs

推荐 16 款 IDEA 插件,让你的开发速度飞起来!

Bruce Duan

idea插件

报志愿|想学区块链,要上什么大学?报什么专业?

CECBC区块链专委会

高考 报考志愿 区块链专业 高校学院

CDN百科第七期 | 关于CDN的原理、术语和应用场景那些事

巨侠说

CDN

JVM系列之:对象的锁状态和同步

程序那些事

JVM GC 同步

Flink Weekly | 每周社区动态更新

Apache Flink

flink

英特尔中国研究院宋继强:芯片、系统、软件成为异构计算的三层级

飞天鱼2017

API接口限流

Bruce Duan

分布式限流 单体限流 限流算法

IO系列——用户空间与内核空间

Java联盟

io 零拷贝 用户空间 内核空间 zero copy

胡继晔:发挥我国优势把依法治网落实到区块链管理中

CECBC区块链专委会

CECBC 胡继晔 依法治网 数字货币监管

IO系列——UNIX五种IO模型

Java联盟

io 多路复用 异步IO

LeetCode001-两数之和-easy

书旅

算法 LeetCode 数据结构与算法

Source Generator:C# 9将迎来编译时元编程-InfoQ