拾光

人生如梦,人生如茶。。。

导航

  • 首页
  • 分类
    • 闲言碎语
    • 聆听
    • 软件分享
    • 亿次元&COS
    • 精品文摘
    • 说一说
    • 相册
  • 页面
    • 听听
    • 朋友圈
    • 留言
    • 友链
  • 朋友圈
  • 友链
  • 登录

Natasha 4.0 探索之路系列(三) 基本的动态编译

admin 2022年 01月 22 日

阅读选项

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>("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 探索之路系列(三) 基本的动态编译的

Natasha 4.0 探索之路系列(三) 基本的动态编译
admin 2022-01-22 软件分享

那年今日
01月
22日
  • 2022年01月22日眼睛为他下着雨,心却为他打着伞,这就是恋爱
  • 2022年01月22日一生里途经的人虽多,但有些人是一阵子,有些人是一辈子
  • 2022年01月22日品味女人:女人兴趣女人味
  • 2022年01月22日逝去的器械,最好不见,最好不念
  • 2022年01月22日关于男子:成熟男子绝对不会做的事
【机器学习基础】无监督学习(1)——PCA 「DP 浅析」斜率优化

微信分享二维码

赞 (0)
打赏
微信打赏
支付宝打赏

猜您想看

ZBLOG PHP主站和二级目录网站伪静态共存设置方法

正常情况下,我...
2022年02月26日

人生哲理:在世的最高境界,就是好好在世

佛光禅师门下有...
2022年01月22日

心灵鸡汤:意境女人

作者:佳墨雅楠...
2022年01月22日

错的时间遇见对的你 (女声版)-牟凡

错的时间遇见对...
2022年03月08日

多年以后-黄静美

多年以后 - ...
2020年12月30日

晚安心语:我想和你一起生活,在某个小镇,共享无尽的黄昏

晚安心语:其实...
2022年01月22日

评论区(暂无评论)

这里空空如也,快来评论吧~

取消回复

我要评论

拾光
如果你错过五点的日出,也许你可以等待六点的夕阳!
99+
文章
99+
评论
7
分类
4
页面
文章分类
  • 闲言碎语 (582)
  • 聆听 (1324)
  • 软件分享 (1048)
  • 亿次元&COS (200)
  • 精品文摘 (4544)
  • 说一说 (119)
  • 相册 (9)
最近文章
  • 一个人的冬 (你出现又离开) - 田园
    2025/05/02 · 暂无评论
  • 连吃醋都要把握分寸 - 田园
    2025/05/02 · 暂无评论
  • 爱过爱错 - 周文凯
    2025/05/02 · 暂无评论
  • 追求 - 卓依婷
    2025/04/21 · 暂无评论
  • 哎呀呀 - 小爱与花儿乐队
    2025/04/21 · 暂无评论
最新评论
  • 灰常记忆
    你这个主题蛮好看的,可以分享下吗?

    2025-03-27
  • admin
    《骆驼祥子》里有一段话: “这世间的真话…

    2024-09-23
  • admin
    谢谢提醒 还记得是2023

    2024-01-24
  • 幻焕
    hey 已经是2024年啦

    2024-01-19
  • admin
    div.s…

    2024-01-16
文章标签
  • 歌曲
  • 一言
  • 原文
  • 分享
  • 照片
  • 二次元
  • typecho
  • 小姐姐
  • 软件
  • 插件
  • wordpress升级
  • 美女
  • wordpress技巧
  • 情感
  • 房子
  • 建筑
  • 别墅
  • WordPress插件
  • Wordpress
  • 视频
友情链接:
拾光
规则之树
幻焕博客
旧时光

© 2025 拾光
Powered by Typecho & BearSimple
湘ICP备18006110号
× 微信二维码

微信扫码联系我

× QQ二维码

QQ扫码联系我