什么是Natasha
Natasha是基于Roslyn 的动态程序构架库,说的直白一点就是将一个或多个cs文件进行动态编译并放入到正在运行的程序中去。例如我们有一个设备库,设备库中的设备会不定期的更新,那我们只需要将平台(展示和调用)完成,每次添加的时候使用Natasha生成设备类别和设备的调用代码,由平台统一调用。这样子就避免了每次调用都要重新生成和更新,每个设备模块都是单独的个体,个体出现bug不影响整个平台的正常工作。
(相关资料图)
Natasha使用场景
- 插件管理,开发一个平台,里面有各式各样的插件,插件可通过引用等方式动态添加
- 在线编码平台,在页面中输入代码,系统根据代码自动生成结果并展示
- 代码生成器,通过编写Entity或读取数据源中的数据来生成代码块,并通过Natasha动态编译到系统中
- 低代码平台
Natasha简单例子
下载最新版 Natasha源码 ,目前最新版本为v5.1.0.0
打开下载好的源码,编译src->CSharp->Natasha.CSharp项目,会生成如下两个dll
- Natasha.CSharp.dll
- Natasha.Domain.dll
创建一个空项目NatashaStudyApplication,然后再创建一个控制台项目NatashaStudyConsole,框架选择了.Net7。
需要额外使用NuGet添加三个引用
添加引用Microsoft.Extensions.DependencyModel,否则初始化时(NatashaInitializer.Preheating方法)会报错。
添加引用Microsoft.CodeAnalysis.CSharp,否则创建编译单元时会报错。
如果使用官网给出的例子,oop.Add方法会提示错误,需要额外安装Microsoft.CodeAnalysis.Common包。
在NatashaStudyConsols项目中创建dlls文件夹,将生成的Natasha.CSharp.dll和Natasha.Domain.dll都赋值到dlls文件夹中,为了防止丢失文件,我全部复制过来了
选择依赖项,点击右键添加项目引用,选择浏览,找到本项目的dlls文件夹,然后把两个dll都进行引入,引入后如图所示:
向Program中的Main中添加代码,官方给出的为声明一个class类,在使用该类时发现回报如下错误:
Predefined type "System.Object" is notdefinedorimported
"object" does notcontain a constructor that takes 0 arguments
该错误的意思是程序没有声明System.Object
本次的例子是基于官网的进行了补充
//得到的结果string result = "";//初始化 Natasha 编译组件及环境NatashaInitializer.Preheating();//创建编译单元,并指定程序集名AssemblyCSharpBuilder oop = new AssemblyCSharpBuilder("myAssembly");//编译单元使用从域管理分配出来的随机域oop.Domain = DomainManagement.Random();//增加代码到编译单元中oop.Add(@"namespace HelloWorld{ public class Test{ public Test(){ Name = null; } public string Name; public void setName(string name){Name=name;} public string getName(){ return ""你好!""+ Name; } } }");//获得Assemblyvar assembly = oop.GetAssembly();// 利用反射实例化var newInstance = assembly.CreateInstance("HelloWorld.Test");//判断实例化是否成功if (newInstance != null) { //获得setName方法 MethodInfo? setNamehod = newInstance.GetType().GetMethod("setName"); if (setNamehod != null) { //利用反射进行赋值 setNamehod.Invoke(newInstance, new object[] { "张三" }); } //获得getName方法 MethodInfo? getNameMethod = newInstance.GetType().GetMethod("getName"); if (getNameMethod != null) { // 获得getName的返回值 result = getNameMethod.Invoke(newInstance, null) as string; }}//打印Console.WriteLine($"{result}");
执行结果结果如下
第二个例子使用官方例子
//在 NDomain1 域内创建一个委托var func = NDelegate.CreateDomain("NDomain1").Func("return \"Hello World!\";");result = func();func.DisposeDomain();//打印Console.WriteLine($"{result}");
执行结果结果如下
关键词: