自Natasha v9.0发布以来,推出了基于Natasha的热执行方案。这项技术允许基于控制台(Console)和新版Asp.net Core架构的项目在运行中动态重编译,以帮助技术初学者、项目初期开发人员等进行快速实验以及试错。
为了更形象地说明热执行,请看下图:
热执行
以下简称热执行为[HE]。当在Asp.net Core接口开发的案例中改变了一个实体类的结构并保存后,可以实时观察到接口返回了最新的实体类结构。这简要阐述了热执行的工作原理,文件发生变化会触发[HE]对项目进行热编译。开发者无论是大改还是小改,只要项目文件(cs)、依赖项目、csproj发生变化,[HE]就会代理整个项目并自动编译输出。对于一些老机器而言,可能[HE]热编译要比[按下F5-程序跑起来]要快得多。
热重载与热执行
有人可能会认为这更像一个完全体的热重载,但实际上并不是。这是与热重载完全不同的技术,[HE]的核心技术是语法树重写与动态编译。而热重载则是对Runtime的程序集进行热更新。热重载严重依赖Debugger组件,且目前从ENC错误代码来看这项技术的限制还是很大的。起初研究了热重载技术,但效果不理想。热重载技术是一项前沿的、边界明确的技术,并不适合敞开手脚快刀阔斧的使用。
指令简介
[HE]使用注释作为热代理指令,这些指令会影响语法树重建以及热编译选项,但不影响程序的发布和使用。目前具体如下:
-
优化级别
使用//HE:Release指令允许在[HE]重编译时使用Release模式进行编译。
-
异步代理
当Main方法中有对象A,A需要延迟卸载,A不干扰new A(即全局可以不只有一个A),此时使用//HE:Async允许[HE]在上一次A对象未完全销毁时异步执行新Main方法。
-
Using排除
由于开发可能会开启隐式using,若开启,则[HE]在代理期间,会加载所有内存中存在的命名空间,因此有概率会出现using二义性引用问题,使用//HE:CS0104可以排除干扰using,例如//HE:CS0104 using1;using2...
-
动态表达式
如果需要在[HE]代理期间动态调试输出一些结果,且不影响程序发布,可以使用//DS或//RS指令输出其后的表达式。例如//DS 1+1在Debug模式下输出2。//RS a.age+b.age在Release输出两个对象年龄相加。
-
参数传递
void ProxyMainArguments()方法将在代理执行之前执行,该方法允许开发者在动态开发中,在[HE]代理期间模拟控制台向main方法中传递参数。
使用
目前该项目支持.NET3.0即以上版本,且.NET5.0版本以上有Source Generator技术加持。
无SG加持的版本
-
引入热执行包:
DotNetCore.Natasha.CSharp.HotExecutor
class Program
{
//...(此处省略其他代码)
}
SG加持(.NET5.0及以上版本)
SG主要是减少了[HE]初始化的一些操作。一些需要手动传递的cancel/dispose实例仍然需要手动传递给[HE]。
简单案例
-
引入SG包:
DotNetCore.Natasha.CSharp.HotExecutor.Wrapper
internal class Program
{
//...(此处省略其他代码)
}
代理新Asp.net Core
[HE]目前不能代理MVC项目和老版的API项目。
public class Program
{
//...(此处省略其他代码)
}
其他项目支持
截至目前,[HE]对Winform的支持不是很好,WPF的代理也很困难。时间和精力有限,不会深入去研究。
鸣谢
感谢九哥的支持。
结尾
遇到问题可以到Natasha Issue区提出反馈。