Natasha 的设计

动态编译

Roslyn 为开发者提供了动态编译的接口, 允许我们以 C# 代码来编写 Emit 或 表达式树生成的程序集, 但是完成一个编译需要诸多步骤, 用户参与的操作也很多, 例如: 格式化整理语法树, 创建编译选项, 填充对应的引用程序集来支持语义检查和编译, 控制输出流等. 其中除了第一个语法树相对简单, 后面都需要开发者摸索完成. 毕竟 Roslyn 的文档不全, 甚至关于它的文档散落在其他边角章节, 比七龙珠都散. 那么在这种情况下使用 Natasha 无疑是非常好的选择.

Natasha 的便捷之处

Natasha 自发版以来,便集成有引用管理, 全局 Using 管理, 域管理, 这让开发者极大的减少了开发前的准备工作, 在便捷编译过程中, Natasha 支持引用覆盖, Using 覆盖,编译流到域的输出, 有了这三大保证, 开发者可更多的关注于动态功能逻辑的开发.

新版 Natasha 新增了语义过滤委托 API 以方便用户根据语义信息定制/重组自己的语法树, 并提供方法支持开发者管理引用版本, 另外保证了3种流的对外输出,即

  • dll : 程序集输出文件
  • pdb : 元数据调试信息
  • xml : 元数据结构及注释

整个编译过程中将会分3阶段抛出异常:

  1. 语法构建阶段,如果出错则抛出异常;
  2. 编译阶段, 如果编译失败则会抛出异常;
  3. 元数据转换阶段, 有些 API 是支持从 Assembly 到其他元数据获取和转换的, 转换失败则抛出异常.

Natasha 基本编译单元

Natasha 的基本编译单元为 AssemblyCSharpBuilder , 该单元整合了编译流程所需要的基本功能, 相比 Natasha 的模板而言, 它则是轻量级,底层的工作单元.

以下是使用方法:

首先引入 DotNetCore.Natasha.CSharp

最基本的编译操作

//Natasha 预热
NatashaInitializer.Preheating(/*...引用添加过滤器...例如:(item, name) => name!.Contains("IO")*/); string code = @"public class A{public string Name=""HelloWorld"";}"; //在花括号范围内圈定域,using 内的方法锁定了域的作用范围.
//Natasha 所有关于 Name 的 Api 如果不指定,默认为 GUID.
using (DomainManagement.Create(domainName)/Random().CreateScope())
{
AssemblyCSharpBuilder builder = new( /*....assenblyName....*/ );
builder.Add(code);
var type = builder.GetTypeFromShortName("A");
//...do sth...
} //手动指定域
AssemblyCSharpBuilder builder = new();
builder.Domain = DomainManagement.Random();
builder.Add(code);
var assembly = builder.GetAssembly();
//...do sth... //直接定位到委托
string code = @"public class A{public string Name=""HelloWorld""; public static string Get(){ return (new A()).Name; }}";
using (DomainManagement.Create("myDomain").CreateScope())
{
AssemblyCSharpBuilder builder = new("myAssembly");
builder.Add(code);
var func = builder.GetDelegateFromShortName<Func<string>>("A","Get");
Assert.Equal("HelloWorld", func()); // √
}
其他 API
//设置输出 dll 文件路径
builder.SetDllFilePath(mydll);
//设置输出 pdb 文件路径
builder.SetPdbFilePath(mypdb);
//设置输出 xml 文件路径
builder.SetXmlFilePath(myxml);
//使用 Natasha 自带的输出路径(请在域和程序集名确定之后调用).
builder.UseNatashaFileOut(); //配置编译选项
builder.ConfigCompilerOption(opt=>opt);
//配置语法树选项
builder.ConfigSyntaxOptions(opt=>opt); //给编译单元添加语义过滤
builder.AddSemanticAnalysistor();
//启/禁用语义过滤
builder.Enable/DisableSemanticCheck(); //添加日志事件
builder.LogCompilationEvent += (log) => { if(log.HasError) Console.WriteLine(log.ToString()); }; //编译事件
builder.CompileSucceedEvent //编译成功触发事件
builder.CompileFailedEvent //编译失败触发事件 //引用行为与程序集加载行为控制
var assembly = builder //委托过滤: 如果发现默认域的引用与定制域中的引用有同名情况,则进入委托处理. 返回一个枚举结果给程序处理.
//PassToNextHandler 结果表示将进入到引用版本行为控制继续处理
.CompileWithReferencesFilter((defaultAssemblyName,domainAssemblyName)=> LoadVersionResultEnum.PassToNextHandler) //引用行为控制, None/UseHighVersion/UseLowVersion/UseDefault(默认使用)/UseCustom 四种控制方法
.CompileWithReferenceLoadBehavior(referenceLoadBehavior) //程序集编译成功后,在域中加载的行为控制,默认为 LoadBehaviorEnum.None (全加载);
.CompileWithAssemblyLoadBehavior(LoadBehaviorEnum.UseDefault) .GetAssembly();

注意: 主域的引用文件和自己创建域的引用文件可能存在同名,但不同版本,此时编译需要 CompileWithReferenceLoadBehavior 来控制引用加载的行为, 举例: RefA(v1.0) 和 RefA(v2.0) 相比, v2.0 中比 v1.0 多了几个功能,几个类,几个接口.... 那么在管理引用的时候, 你就要根据自身的代码情况进行管理, 比如你的代码用到了 v2.0 的新类,新功能, 那么就要屏蔽掉 v1.0.

覆盖全局 using
//-------------------主域 using -------------------- 定制域 using ------------------------------- 代码脚本 ---------------
string code = DefaultUsing.UsingScript + builder.Domain.UsingRecorder.ToString() + "namespace{ public class xx..... }";

域中的 UsingRecorder 会记录编译之后产生的 using, 自动管理.

结尾

大家在使用动态编译时, 要尽可能做到"隔离", 一旦依赖和引用版本多了, 对于动态开发来讲,就是一场灾难.

以上是使用 Natasha 关于动态编译的最基本使用方法, 下一篇将讲解 Natasha 高级 API 的使用.

Natasha 4.0 探索之路系列(三) 基本的动态编译的更多相关文章

  1. Natasha 4.0 探索之路系列(一) 概况

    Natasha 简介 Natasha 是一个基于 Roslyn 的动态编译类库, 它以极简的 API 完成了动态编译的大部分功能, 使用它可以在程序运行时编译出新的程序集. Natasha 允许开发人 ...

  2. Natasha 4.0 探索之路系列(二) "域"与插件

    域与ALC 在 Natasha 发布之后有不少小伙伴跑过来问域相关的问题, 能不能兼容 AppDomain, 如何使用 AppDomain, 为什么 CoreAPI 阉割了 AppDomain 等一系 ...

  3. Natasha 4.0 探索之路系列(四) 模板 API

    Natasha 模板 Natasha 在编译单元的基础上进行了封装整理, 并提供了多种模板帮助开发者构建功能. 使用此篇的 API 前提是您对 C# 非常熟悉, 对系统的一些类型足够了解. 据此 Na ...

  4. Microsoft Enterprise Library 5.0 系列(三)

    一.简介及用途 在实际的项目开发中,我们总会需要对数据进行验证,以保证数据的可靠性,而为了使这些验证可以在不同的地方进行复用(如winform.web.WPF等),就需要将验证进行封装,EntLib的 ...

  5. 【Android Studio探索之路系列】之六:Android Studio加入依赖

    作者:郭孝星 微博:郭孝星的新浪微博 邮箱:allenwells@163.com 博客:http://blog.csdn.net/allenwells github:https://github.co ...

  6. Web 开发人员和设计师必读文章推荐【系列三十】

    <Web 前端开发精华文章推荐>2014年第9期(总第30期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  7. WCF 4.0 进阶系列 -- 随笔汇总

    WCF4.0 进阶系列–前言 WCF4.0 进阶系列--第一章 WCF简介 WCF4.0进阶系列--第二章 寄宿WCF服务 WCF4.0进阶系列--第三章 构建健壮的程序和服务 WCF4.0进阶系列- ...

  8. MyBatis学习系列三——结合Spring

    目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring MyBatis在项目中应用一般都要结合Spring,这一章主要把MyBat ...

  9. MySQL并发复制系列三:MySQL和MariaDB实现对比

    http://blog.itpub.net/28218939/viewspace-1975856/ 并发复制(Parallel Replication) 系列三:MySQL 5.7 和MariaDB ...

随机推荐

  1. outlook2007邮件里的图片显示不出来

    outlook2007邮件里的图片显示不出来,这是为啥? 以图片为附件的形式进行传送吧,这样在收件箱里就能在线看图片了,不用担心看不到图片

  2. 一个VS主题网站https://studiostyl.es/

    地址: https://studiostyl.es/ 用法: 工具->导入和导出设置->导入选定的环境设置->是,保存我当前的设置->选择下载的主题文件,完成.

  3. 【LeetCode】332. Reconstruct Itinerary 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 后序遍历 相似题目 参考资料 日期 题目地址:htt ...

  4. 【LeetCode】643. 子数组最大平均数 I Maximum Average Subarray I (Python)

    作者: 负雪明烛 id: fuxuemingzhu 公众号:每日算法题 目录 题目描述 题目大意 解题方法 方法一:preSum 方法二:滑动窗口 刷题心得 日期 题目地址:https://leetc ...

  5. 【LeetCode】6. ZigZag Conversion Z 字形变换

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:字形变换,ZigZag,题解,Leetcode, 力扣,P ...

  6. Pydantic使用

    Pydantic可以在代码运行时提供类型提示, 数据校验失败时提供友好的错误提示, 使用Python的类型注解来进行数据校验和settings管理 一般使用 from datetime import ...

  7. Reflection 基础知识(二)

    Proxy 定义 Proxy用于修改对象的某些行为,获取值,设置值等 let p = new Proxy(target, handler); target 用Proxy包装的目标对象(可以是任何类型的 ...

  8. vue中使用JSX报错,如何解决

    Support for the experimental syntax 'jsx' isn't currently enabled (32:12): 30 | }, 31 | render() { & ...

  9. Eclipse 常用快捷键大全

    15 个 Eclipse 常用开发快捷键使用技巧 1.alt+? 或 alt+/:自动补全代码或者提示代码 2.ctrl+o:快速outline视图 3.ctrl+shift+r:打开资源列表 4.c ...

  10. 使用 jQuery对象设置页面中 <ul> 元素的标记类型,并使用 DOM 对象设置 <li> 元素的浮动属性和右边距。使用jQuery 对象和 DOM 对象设置页面元素属性

    查看本章节 查看作业目录 需求说明: 使用 jQuery对象设置页面中 <ul> 元素的标记类型,并使用 DOM 对象设置 <li> 元素的浮动属性和右边距.使用jQuery ...