使用Roslyn动态编译代码
什么是Roslyn
从C# 6 开始,编译器被完全用C#重写并且模块化,这个模块化的编译器就是Roslyn。利用Roslyn,我们可以方便地在我们的程序中动态编译代码,即,把代码当做数据传递给Roslyn编译器,得到编译后的程序集。
安装并引用Roslyn
在开始使用之前,先在使用Nuget安装Microsoft.CodeAnalysis.CSharp
之后在命名空间声明中,添加
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
编译流程
在使用Roslyn之前,对编译器如何把源代码翻译成MSIL的过程,即,编译流程有个大概了解,对我们得心应手使用这个工具非常有帮助。
源文件读取
编译的第一步是读取源文件,在Roslyn里面用SourceText表示源文件**,支持多种不同的源文件读取,包括从文件流读取、直接在源代码指定literal的方式,像以下两种方式常用
SourceText st; //从文件流读取using (var fs = new FileStream(filePath, FileMode.Open)){st = SourceText.From(fs);}st = SourceText.From(@"public class TestClass {}"); //直接用literal方式指定源代码
语法树解析
读取源文件之后,我们需要根据源文件解析生成语法树。在Roslyn里面用SyntaxTree表达语法树。Roslyn在这一步中将会检查语法的合理性,如果有语法错误,可以通过调用SyntaxTree的方法GetDiagnostics查看。在生成语法树的时候,可以通过传入的ParseOption控制编译语言版本设定、预处理变量设定,等。
st = SourceText.From(@"public class TestRoslyn { public void Test(){ Console.FakeMethod(); } }"); //没有引用Console,同时Console里面没有FakeMethod这个方法,但是语法解析不会报错,只要语法是正确的就没问题。CSharpParseOptions option = new CSharpParseOptions(LanguageVersion.CSharp8, preprocessorSymbols: new List<string>() { "Debug"}); //确定使用C# 的版本和传入的预编译量
var tree = CSharpSyntaxTree.ParseText(st, option);
Debug.Assert(tree.GetDiagnostics().ToList().Count == 0);
语义解析
语法解析确保了我们的源代码符合C#的语法,比如,有相对应的{},每个字句后面有;,等。但是语法正确只是第一步,我们需要进一步确保我们每条调用语句都是正确的,即,我们引用的类,已经正确的引用到了我们的编译中并且声明在命名空间引用中,同时我们每个语句调用必须调用在正确的函数上,必须传递正确的参数。要做到这一步,我们需要的是语义解析。
在Roslyn使用CSharpCompilation完成语义解析,这是一个静态类,在创建的时候我们可以传入的参数有很多,但最主要的就是,想要创建的模块名称、参与语义解析的语法树(可以有多个语法树,代表可以编入同一个模块的不同文件)、引用的程序集(mscorlib.dll是必须的)和目标类型(dll或者exe)。
var compileOption = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create(
"class1",
new List<SyntaxTree> { tree }, //这是前面生成的语法树
new List<MetadataReference>() { MetadataReference.CreateFromFile(typeof(int).Assembly.Location) }, //这是一个得到msconlib的好办法
compileOption);
Debug.Assert(tree.GetDiagnostics().ToList().Count == 0); //如果之前有引用缺失、调用方法错误,这里就会体现出来
生成IL代码到程序集文件
最后我们把代码发射到程序集文件(可以是exe也可以是dll),同时可以生成pdb文件。
var assemblyPath = @"D:\Roslyn\class1.dll";
var pdbPath = @"D:\Roslyn\class1.pdb";
var result = compilation.Emit(assemblyPath, pdbPath); //result表明了执行是否成功
至此,一个动态编译代码生成程序集的流程就完成了。
用途
生成了dll之后,我们可以通过反射加载,或者直接在工程文件中引用的方式使用。
我们一般在构建脚本系统的时候会较多的使用动态代码编译的方法,通过监听脚本源文件,动态的生成程序集,给脚本系统添加不同的功能。
希望对大家能有点帮助。
使用Roslyn动态编译代码相关推荐
- 使用Roslyn动态编译和执行
1. 安装nuget package 2.使用Roslyn 动态执行 var engine = new Roslyn.Scripting.CSharp.ScriptEngine();engine.Cr ...
- python 动态编译代码_使用PyQt(Python+Qt)+动态编译36行代码实现的计算器
PyQt是基于跨平台的图形界面C++开发工具Qt加Python包装的一个GPL软件(GPL是GNU General Public License的缩写,是GNU通用公共授权非正式的中文翻译),Qt基于 ...
- python 动态编译代码_编译Python代码以使用Cython静态链接可执行文...
经验丰富的问题??显然来自链接器(gcc在引擎盖下启动了一个链接器,看到它 – 只需用详细模式启动带有-v的gcc).那么让我们先简要提醒链接过程如何工作: 链接器保留其需要解析的所有符号的名称.在开 ...
- C#实现动态编译代码
/*------------------------------------------------------------------------------* Copyright (C) 2013 ...
- python 动态编译代码,Python:在运行时动态创建函数
How to dynamically create a function in Python? I saw a few answers here but I couldn't find one whi ...
- NetCore基于Roslyn的动态编译实现
目录 一. AvalonEdit文本器 1.功能实现 2. 高亮 3. 代码提示 4. 动态编译 1)依赖项初始化 2) 编译函数 二. 运行效果展示 三. 源码链接 四. 参考资料 一. Avalo ...
- 基于roslyn的动态编译库Natasha
人老了,玩不转博客园的编辑器,详细信息转到:https://mp.weixin.qq.com/s/1r6YKBkyovQSMUgfm_VxBg 关键字:Github, NCC, Natasha,Ros ...
- 基于 Roslyn 实现动态编译
基于 Roslyn 实现动态编译 Intro 之前做的一个数据库小工具可以支持根据 Model 代码文件生成创建表的 sql 语句,原来是基于 CodeDom 实现的,最近改成使用基于 Roslyn ...
- eclipse编译java项目class文件_动态编译 Java 代码以及生成 Jar 文件
导读: 最近在看 Flink 源码的时候发现到一段实用的代码,该代码实现了 java 动态编译以及生成 jar 文件.将其进行改进后可以应用到我们的平台上,实现在平台页面上编写 java 代码语句,提 ...
- Java脚本引擎执行js代码以及动态编译
Java脚本引擎执行js代码 一.概述 JAVA脚本引擎是从JDK6.0之后添加的新功能. 使得 Java 应用程序可以通过一套固定的接口与各种脚本引擎交互,从 而达到在 Java 平台上调用各种脚本 ...
最新文章
- web客户端 http error 413
- 【 MATLAB 】通过不同样本数的同一个有限长序列作 DTFT 对比
- 【深入Java虚拟机JVM 03】Java内存模型
- 实验1 熟悉实验环境
- 数据统计告诉你,程序员是不是35岁就退休
- oracle apex 日志,oracle-apex - 在oracle apex报告中显示员工记录或经理记录及其员工 - SO中文参考 - www.soinside.com...
- 安卓 qemu 运行linux,在Qemu的beagleboard上运行Android
- 网易云音乐ncm文件格式转mp3格式教程
- java解四元一次方程
- 全方面对比流行报表开发工具,哪一个才是你的菜?
- 2020牛客暑期多校训练营(第九场)I	.The Crime-solving Plan of Groundhog
- qq邮箱收信服务器imap,普通IMAP、POP邮箱的设置 教你使用iPhone邮件客户端管理QQ邮箱...
- Google VR 学习小结
- outlook从服务器中恢复已删除项目,恢复邮箱中的已删除邮件:Exchange 2013 帮助 | Microsoft Docs...
- 在Java中计算一元线性回归
- html5新特性(一)
- 第一章 略说中医的学习与研究(4)
- 如何实现从CTO到CEO的跨越(红色标注是我关注的点)
- java程序框图 质数_判断质数的程序框图和算法
- 【webrtc】fdk-aac 编解码库cmake和 gn编译
热门文章
- 联想K31笔记本完全拆解,装不回去了。想做个电视机或者显示器
- MATLAB系统辨识工具箱学习,详细教程!
- ui设计app设计风格有哪些?ui设计app界面设计流程是什么?
- 计算机网络被限速,电脑网速被限制怎么办
- 办公软件是计算机吗,什么是办公软件_IT /计算机_资料
- ORA-12162: TNS:net service name is incorrectly specified 错误解决
- EJB是什么,以及weblogic和tomcat的区别
- C库-atoi(), atol(), atoll(), atof(), ceil(), ceilf(), ceill()
- C#+ AE实现地图注记功能
- 计算机应用基础 (2013),计算机应用基础