[.NET大牛之路 006] 了解 Roslyn 编译器
.NET大牛之路 • 王亮@精致码农 • 2021.07.09
维基百科对编译器的解释是:编译器是一种程序,它将某种编程语言编写的源代码(原始语言)转换成另一种编程语言(目标语言)。编译是从源代码(通常为高阶语言)到能直接被计算机或虚拟机执行的目标代码(通常为低阶语言或机器语言)的翻译过程。
在 .NET 平台中,在执行模型的不同阶段有两个不同的编译器:一个叫 Roslyn 编译器,负责把 C# 和 VB 代码编译为程序集;另一个叫 RyuJIT 编译器,负责把程序集中的 IL(中间语言) 代码编译为机器码。
本文先介绍 Roslyn 编译器。我们不必深入研究它的工作原理,但要了解它的工作机制,要知道它可以用来做什么事情。
最初 C# 语言的编译器是用 C++ 编写的,后来微软推出了一个新的用 C# 自身编写的编译器:Roslyn,它属于自举编译器。
所谓自举编译器就是指,某种编程语言的编译器就是用该语言自身来编写的。自举编译器的每个版本都是用该版本之前的版本来编译的,但它的第一个版本必须由其它语言编写的编译器来编译,比如 Roslyn 的第一个版本是由 C++ 编写的编译器来编译的。很多编程语言发展成熟后都会用该语言本身来编写自己的编译器,比如 C# 和 Go 语言。
在 .NET 平台,Roslyn 编译器负责将 C# 和 VB 代码编译为程序集。
大多数现有的传统编译器都是“黑盒”模式,它们将源代码转换成可执行文件或库文件,中间发生了什么我们无法知道。与之不同的是,Roslyn 允许你通过 API 访问代码编译过程中的每个阶段。
它的工作机制是管道式的,整个工作管道包含四个阶段,每个阶段都是一个独立的模块,每个模块都提供了相应的 API。集成开发环境(IDE)可以利用这些 API 提供方便的工具以提高开发效率,如代码高亮、智能提示、重构工具、性能分析工具等。此外,通过 Roslyn,开发者可以在自己的程序中使用编译器,将编译器作为一种服务来使用。
下图描绘了 Roslyn 工作管道的各个阶段和各阶段对应的 API,以及各 API 可为 IDE 提供的对应功能:
Parser(解析)阶段,根据语言语法对源代码进行解析,将源代码转换为层次化的标记集合,形成语法树。语法树 API 用于在源代码编辑器中格式化、着色和代码大纲。
Declaration(声明)阶段,分析所有引用和导入的元数据,形成层次化的符号表。在编辑器和对象浏览器中的
Navigation To
特性使用这个 API。Bind(绑定)阶段,对标记集合和符号表进行匹配。编辑器中的
Find All References
、Rename
、Quick Info
和Extract Method
等特性使用这个 API。Emit(生成)阶段,生成 IL 托管模块,将一个或多个 IL 托管模块和嵌入资源合并成程序集。编辑器中的
Edit and Continue
利用这个特性完成一次新的编译。
Roslyn 是少数几个让你有机会观察所有编译阶段和中间结果的编译器之一,它提供的这些 API 可以为语言服务实现丰富的功能。例如,代码高亮使用语法树,对象浏览器使用分层符号表。
下面我们来做一个简单的示例,利用 Roslyn 提供的 API 来动态生成代码。
创建一个控制台应用程序 ConsoleApp
,编辑 Program.cs
的代码如下:
using System;
namespace ConsoleApp
{
partial class Program
{
static void Main(string[] args)
{
HelloFrom("Generated Code");
Console.ReadKey();
}
static partial void HelloFrom(string name);
}
}
再创建一个 .NET Standard 类库,取名 MyGenerator
,并添加两个 NuGet 包,项目文件内容如下:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.10.0" />
</ItemGroup>
</Project>
然后在 MyGenerator
项目中添加一个 Generator.cs
文件,代码如下:
using Microsoft.CodeAnalysis;
namespace MyGenerator
{
[Generator]
public class Generator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
}
public void Execute(GeneratorExecutionContext context)
{
// find the main method
var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);
// build up the source code
string source = $@"
using System;
namespace {mainMethod.ContainingNamespace.Name}
{{
public static partial class {mainMethod.ContainingType.Name}
{{
static partial void HelloFrom(string name)
{{
Console.WriteLine($""Generator says: Hi from '{{name}}'"");
}}
}}
}}
";
// add the source code to the compilation
context.AddSource("generatedSource", source);
}
}
}
这里的 source
是我们的动态组装的代码,在实际应用中还可以从数据库或文本中读取代码片段。
最后在 ConsoleApp
项目中引用 MyGenerator
类库,并参照如下代码设置 OutputItemType
和 ReferenceOutputAssembly
属性:
<ItemGroup>
<ProjectReference Include="..\MyGenerator\MyGenerator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
运行 ConsoleApp
,可以看到控制台输出如下内容:
Roslyn 的功能非常强大,这个示例只是演示了 Roslyn 的一个非常简单的功能和用途。
Roslyn 不只是一个编译器,还是一个现成的框架,它使得在 .NET 平台上创建自己的语言服务变得更加容易。你可以使用 Roslyn 编译器的 API 在 .NET 平台上开发一个完整的应用程序,甚至创建你自己的 IDE、编写你自己的编译器、解释器或分析器来编译和运行你自己的编程语言。
[.NET大牛之路 006] 了解 Roslyn 编译器的更多相关文章
- [.NET大牛之路 007] 详解 .NET 程序集
.NET大牛之路 • 王亮@精致码农 • 2021.07.13 上一篇我们介绍了 Roslyn 编译器,我们知道,我们编写的 C#/VB 代码经过 Roslyn 编译器编译后会生成程序集文件.按照之前 ...
- [.NET大牛之路 005] .NET 的执行模型
.NET大牛之路 • 王亮@精致码农 • 2021.07.06 前面我们介绍 .NET 历史时讲过,微软基于 .NET Framework 重新设计并创造了跨平台的 .NET Core,目前已经发展到 ...
- [ASP.NET MVC 大牛之路]01 - 开篇
匆匆2014,转眼就到末尾了.在这一年,你还有哪事情些想做而没有做? 2014年在我身上发生了两件意义重大的事,一是正月初一宝宝出生,我升级成为了爸爸:二是进入了一家创业公司,成为了技术负责人. 去年 ...
- [ASP.NET MVC 大牛之路]02 - C#高级知识点概要(1) - 委托和事件
在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...
- [ASP.NET MVC 大牛之路]03 - C#高级知识点概要(2) - 线程和并发
本人博客已转移至:http://www.exblr.com/liam 我也想过跳过C#高级知识点概要直接讲MVC,但经过前思后想,还是觉得有必要讲的.我希望通过自己的经验给大家一些指引,带着大家一起 ...
- [ASP.NET 大牛之路]02 - C#高级知识点概要(1) - 委托和事件
在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...
- Roslyn 编译器和RyuJIT 编译器
Roslyn 编译器 https://msdn.microsoft.com/zh-cn/library/mt162308.aspx https://blogs.msdn.microsoft.com/d ...
- [ASP.Net] 转 > ASP.NET MVC 大牛之路
URL: http://www.cnblogs.com/willick/ [ASP.NET MVC 大牛之路]01 - 开篇 [ASP.NET MVC 大牛之路]02 - C#高级知识点概要(1) - ...
- [.NET大牛之路 001] .NET 其名
本文来自『.NET大牛之路』星球的分享 大家好,这是 .NET 大牛这路的第 1 篇文章.大家期待已久的课程今天正式开始了.既然我们整个体系课程都将围绕 .NET 展开,那我们今天就先聊一聊 .NET ...
随机推荐
- [.NET大牛之路 001] .NET 其名
本文来自『.NET大牛之路』星球的分享 大家好,这是 .NET 大牛这路的第 1 篇文章.大家期待已久的课程今天正式开始了.既然我们整个体系课程都将围绕 .NET 展开,那我们今天就先聊一聊 .NET ...
- 测试MySQL锁的问题
测试MySQL锁的问题 目录 测试MySQL锁的问题 1 Record Lock 2 Next-Key Lock 2 死锁测试 InnoDB支持三种行锁: Record Lock:单个行记录上面的锁 ...
- Java 7的javax.net.ssl.SSLHandshakeException
Java 7的javax.net.ssl.SSLHandshakeException 现象:Java7通过httpsURLConnection建立HTTPS连接,异常如下: javax.net.ssl ...
- 仅使用JsonUtility和File类实现Json数据读写
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using S ...
- 17、ansible配置管理
17.1.前言: 1.说明: ansible是自动化运维工具,基于Python开发,实现了批量系统配置.批量程序部署.批量运行命令等功能. ansible是基于模块工作的,本身没有批量部署的能力,真正 ...
- POJ 1039 直线和线段相交
题意: 题意很好理解,从左边射过来的光线,最远能经过管道到右边多少距离. 分析: 光线一定经过一个上端点和一个下端点,这一点很容易想到.然后枚举上下端点即可 #include <iostream ...
- nginx用Certbot配置免费SSL证书(ngx_http_ssl_module模块)
一.准备工作 1.先安装nginx https://files.cnblogs.com/files/blogs/676936/nginx-1.18.0.sh #nginx-1.18.0版安装脚本2.在 ...
- Docker搭建EFK日志收集系统,并自定义es索引名
EFK架构图 一.EFK简介 EFK不是一个软件,而是一套解决方案,并且都是开源软件,之间互相配合使用,完美衔接,高效的满足了很多场合的应用,是目前主流的一种日志系统. EFK是三个开源软件的缩写,分 ...
- 海量数据Excel报表利器——EasyExcel(一 利用反射机制导出Excel)
EasyExcel 写入(导出) 互联网的精髓就是共享,可以共享技术.共享经验.共享情感.共享快乐~ 很多年前就有这个想法了,从事IT行业时间也不短了,应该把自己工作和业余所学习的东西记录并分享出来, ...
- RabbitMQ 常用知识点总结
基础 为什么使用 MQ? 1.削峰:在某个模块接收到超过最大承受的并发量时,可以通过 MQ 排队来使这些削减同一时刻处理的消息量.减小并发量. 2.解耦:在发送 MQ 处理业务时,可以使业务代码与当前 ...