Natasha 4.0 探索之路系列(一) 概况
Natasha 简介
- Natasha 是一个基于 Roslyn 的动态编译类库, 它以极简的 API 完成了动态编译的大部分功能, 使用它可以在程序运行时编译出新的程序集.
- Natasha 允许开发人员直接使用 C# 代码即可编写运行时的功能, 避免了 Emit 的学习,开发,维护的成本.
- Natasha 的编译单元的基本输出是程序集, 程序集加载在域中, 使用该类库可以创建域,并在不同的域内创建新的功能, 也支持可以卸载域.
- Natasha 为开发人员提供了插件管理的功能, 并内置解析依赖的功能, 我们可以有针对性的加载和卸载插件及其依赖.
- 使用 Natasha 我们可以快速的实现 mapper/类库粘合/业务逻辑组装/动态代理/协议转换等等, 使用 Natasha 需要一定的编程基础,有动态编译经验相关的实践.尽管 Natasha 可以输出详细日志,但是动态功能的开发本应该是逻辑畅通,代码规范的,如果你不能保证代码是畅通的,且没有动态编译的思维可以先找相关的文章进行学习.
Natasha 进化
Natasha 自 v3.0.0 版本之后,进行了比较大的革新,以下我列举一些比较重要的:
-
移除对 standard2.0 / core2.1-3.0 的支持, 目前支持的版本为: net3.1/5.0/6.0, 兼容版本已归档至其他分支.
Runtime 是 Natasha 的强依赖, .NET 从 3.0 起, Runtime 升级了很多新的特性, 比如支持可空引用及元数据处理, 支持 ALC 高级特性, 方便的插件依赖解析方案等等, 另外由于个人精力有限, 最终决定从分水岭 3.1 开始做兼容. -
语义过滤, 自 v3.0.0 以后, Natasha 新增了语义层, 这让 Natasha 显得更加智能, 我们可以根据自己的需求去解析和重组语法语义.
比如 Natasha 内置的语义处理, 其中有一个功能是将无用的 using 移除掉, 只保留有用的 using. 大大减少了日志输出的代码, 让开发者一眼看到有用的代码逻辑.
编译一段代码, 需要引用元数据,需要准备 using,需要写正确的代码,最后是输出方式, 为了让开发者以最快速度上手, Natasha 解决了元数据引用问题,以及 using 覆盖问题, 另对外提供了输出 API, 理论上开发者需要关注的是自己如何编写一段动态代码, 如何与运行时其他功能接洽配合.另针对命名空间滥用导致的多义性引用问题, 我们提供了语义扩展包
Natasha.CSharp.Extension.Ambiguity
-
性能优化, 优化是 Natasha 一直在做的事情, Natasha 在预热方法上进行了一些并发的改造, 以便让相互无关的任务并行初始化, 除此之外也移除了 AdWorkspace 代码, 这些带码均由高性能的方案取代. 针对性能敏感场景, 我们增加了预热时全局修剪错误语义,以及禁用语义过滤的 API, 以便让编译更快的发生.
-
新特性支持. 支持 c# 最高语言版本, 支持可空引用的编译(默认关闭), dll/pdb/xml 文件手动选择生成. Natasha 4.0 的源码使用了可空引用支持, 因此支持可空引用项目的接入和使用, 在方法调用的上下游明确了可空界限. 但在动态编译层面,尝试可空引用的元数据解析功能时,我遇到了无法解决的难题, 可空引用的顶层泛型传递是无法正确解析的, 因此在 Action<string?> 等元数据解析中,无法得到正确结果, 另外方法返回值可空引用解析也未找到方法, 综上 Natasha 默认关闭了动态编译初始化中的可空引用的选项, 开发者需要自行开启.
-
重构引用管理, 4.0 重构了 Natasha 的引用管理, 经过探索我们最终选定以 AssemblyName 作为引用版本管理的依据, 并在预热过程中采用只读上下文解析引用.
-
重构插件管理, 4.0 重构了 Natasha.Domain 域实现, 摘除了对引用管理的耦合, 让 NatashaDomain 更专注于程序集及其依赖的加载与卸载, 此次对外提供了4个方法以便于用户在加载插件时管理不同版本的依赖.
-
重构日志模块, 4.0 版本后日志将由用户自行控制写入和获取, 对外提供编译后的日志处理事件, Natasha 将不再负责日志的 IO 部分.
-
重构异常模块, 4.0 重构了 Natasha 的编译单元, 其中语法转换阶段如果出错会抛出异常, 之后编译不成功也会抛出异常, 并提供编译成功和失败事件.
Natasha 实战应用
Natasha 已经在网友公司及我司得到了广泛应用, 比如:客户端脚本定制, 动态计分系统, 低代码应用中的逻辑组装与编译, 类库中字符串到表达式树的转换, 基于算法的高性能只读并发字典, 忽略类库版本的代码粘合剂, 实体映射, 动态路由, 动态RPC, 动态定时任务等等.
Natasha 与其他技术
-
SG(Source Generetor)
首先来讲 Natasha 与 SG 有重叠的部分, 但也有各自取代不了的地方. 我认为比较好的组合是, SG 提供静态约束, Natasha 来提供动态实现.
-
AOT
Natasha 是尽可能覆盖全面的程序集和引用, 剪裁需谨慎, 另外 AOT 不会取代动态编译, 只会平行发展.
Natasha 未来规划
Natasha 完成了自己的核心任务,但它还有很长一段的路要走, 期待大家的反馈.
后续 Natasha 还有一些方案需要调研, 一些应用需要开发, 例如:域的强制卸载方案, 基于 Asp.net 的动态开发框架, 高度灵活的高性能实体映射库等.
下一篇将介绍 Natasha 的域组件与插件编程.