欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基于roslyn的动态编译库Natasha

程序员文章站 2022-04-29 14:25:28
人老了,玩不转博客园的编辑器,详细信息转到:https://mp.weixin.qq.com/s/1r6YKBkyovQSMUgfm_VxBg 关键字:Github, NCC, Natasha,Roslyn, .NET Core2.0,.NET Core2.1,.NET Core2.2,.NET C ......

 

 

人老了,玩不转博客园的编辑器,详细信息转到:https://mp.weixin.qq.com/s/1r6ykbkyovqsmugfm_vxbg

 

 

 

关键字:github, ncc, natasha,roslyn, .net core2.0,.net core2.1,.net core2.2,.net core2.3, standard2.0, 动态编译,运行时脚本,高性能。

​一、 前言

 

        对于开源贡献者,emit和表达式树不是陌生的字眼,il的动态特性为封装工作带来了极大的方便,会emit的开发者可以说驾驭了大部分的高性能、高动态的编程技巧。纵观ef、dapper、json.net等第三方常用库,哪个能脱离emit而独善其身,也正因如此,幸福了一批批懒癌患者,包括我这个懒癌中晚期患者(这里给各位病友问好),与此同时本人对封装有着莫名其妙的执念,就在两支怪力的驱使下走上了对emit的不归路.

 

旧版natasha始于2016年,当时是对emit进行的封装,中途经有柠檬的提醒完善了ut和兼容性等工作,后由victor.x.qu补充了文档,后经orm实战。

 

 

二、emit非银弹

 

        经历过重重思考和实践,emit不是动态的最佳实践,简单的从以下几个角度来讲:

 

    • 调优:

 

    • dup : emit中的dup指令优化在是由开发者控制的,在熟悉指令操作的同时又给开发者带来了额外的优化工作。

       

    • if/while/for :不得不说il可以透过代码看本质,指令就是这样的,在条件分支上,标签跳转的形式使得逻辑执行灵活多变。这样除了栈的操作之外,还要关注标签的位置和跳转语句的优化,另外还要清晰的记得你的各个分支。

       

    • 并发字典与算法优化 :这一点是出自我的极端,在对象成员的赋值/加载等操作面前,并发字典像是一场灾难,卖尽气力优化的动态执行,却被某些数据结构所糟蹋。至于算法与动态编译结合起来,应该没几个病友做过,各位如果有兴趣的话可以慢慢体会。

       

 

    • 兼容性:

 

    • 结构体 : 类与结构体在操作指令上有着诸多的不同,开发者不仅仅要熟悉对类的操作指令,还要对结构体做出兼容,诸如ldflda、 ldloca、constrained等指令,对于开发者来说并不是一件省心的事。

       

    • 类型转换 : .net中的类型转换不仅仅有指令级的转换,standard还提供了诸多方法支持不同类型之间的转换,因此你还需要花一些功夫去处理这些。

       

    • 语法糖 : 一切语法糖在emit面前都要还原,比如可空类型语法糖,对象比较语法糖,类型比较语法糖等等,无疑会大大增加兼容工作的负担(core3.0的可空引用我还没有做测试)。

       

 

    • 构建难度:

 

    • 深度克隆 : 深度克隆是动态编程的一个典型实战,如果各位病友坚持用emit挑战的话,可以没病走两步,走两步。

       

    • 深度构建 :一旦遇到了动态构建动态场景,那么这个复杂度难以想象。

       

    • 猜错误 : emit并没有很好的友情提示,没有语法检查,而被程序锻炼成老猎手一定要付出很多代价。

       

 

    • 维护升级:

 

    • 后续开发 :接手emit代码是一件令人纠结的事,当量变引起质变的时候,从兴奋到苦不堪言这种事情并不是没有发生过,尤其是现在.net开源工作者都比较独立,没有凝聚力和氛围,人的生命以及精力是有限的。

       

    • 传承  :由上面诸多信息也可见,在新技术的冲击下,在令人不安的环境下,在孤独的夜里,传承也是个问题。

       

 

 

尽管表达式树已经帮我们做了一些工作,但复杂场景和使用习惯仍然封印着开发者的大脑。

 

 

三、狙击暴君

 

        roslyn到如今已经耳熟能详了,编译被当作成服务对外开放,让不少开发者从中受益,但由于文档不全,实例不充分,从开始一直到2018年期间,对于懒癌开发者来说,基于roslyn开发都是一件憋手的事情(例如一些必备操作文档,在2019年今年5月份才提上日程)。natasha使用roslyn做为编译引擎,不仅仅在动态构建上进行了人性化升级,还在功能上进行了简化。您不仅可以使用natasha轻松的构建类、结构体、方法、接口、抽象类,还可以轻松的继承类、重载方法、实现接口、抽象类等等,技术较新,仅支持.standard2.0。

 

        项 目 地 址:https://github.com/dotnetcore/natasha

        nuget索引:dotnetcore.natasha  (正式版1.0.0.0)

 

(娜塔莎)(原型苏联红军第25步兵师的中尉柳德米拉·帕夫利琴科,一名出色的女狙击手)

 

 

使用natasha你需要关注:

 

  1. 在您的工程文件里添加这个节点:<preservecompilationcontext>true</preservecompilationcontext>

     

  2. 了解wiki中反解器的概念及使用。    

     

  3. 注意命名空间,自动补充命名空间目前尚未支持,需要您手动操作,使用using方法添加。

     

  4. 想尽一切办法拼接字符串,目前符合csharp7.3或以下c#版本的都行。

     

  5. 编译模式有区分:streamcomplier内存流编译/filecomplier文件流编译, 文件流编译的内容,可以被动态调用。当你想动态编译类b的时候使用类a,那类a就需要使用文件流编译,相当于dll动态加载到运行时。

     

  6. 使用natasha中的operator来构建你的动态内容。

 

四、性能

 

        这几年随着.net架构引擎的不断升级,dynamic、emit执行性能已经得到了大幅度提升,roslyn也不例外,之前官方给过性能测试截图,上面显示是比emit快一点,个人的基准测试要等下一个benchmark版本,从耗时的角度来说roslyn <= emit (roslyn有指定release模式编译),所以大家根本不用关心性能问题。

 

 

五、使用案例