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


Natasha 简介

  • Natasha 是一个基于 Roslyn 的动态编译类库, 它以极简的 API 完成了动态编译的大部分功能, 使用它可以在程序运行时编译出新的程序集.
  • Natasha 允许开发人员直接使用 C# 代码即可编写运行时的功能, 避免了 Emit 的学习,开发,维护的成本.
  • Natasha 的编译单元的基本输出是程序集, 程序集加载在域中, 使用该类库可以创建域,并在不同的域内创建新的功能, 也支持可以卸载域.
  • Natasha 为开发人员提供了插件管理的功能, 并内置解析依赖的功能, 我们可以有针对性的加载和卸载插件及其依赖.
  • 使用 Natasha 我们可以快速的实现 mapper/类库粘合/业务逻辑组装/动态代理/协议转换等等, 使用 Natasha 需要一定的编程基础,有动态编译经验相关的实践.尽管 Natasha 可以输出详细日志,但是动态功能的开发本应该是逻辑畅通,代码规范的,如果你不能保证代码是畅通的,且没有动态编译的思维可以先找相关的文章进行学习.

项目链接地址: https://github.com/dotnetcore/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 等元数据解析中,无法得到正确结果, 另外方法返回值可空引用解析也未找到方法, 综上 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 的域组件与插件编程.