基于roslyn的动态编译库Natasha
人老了,玩不转博客园的编辑器,详细信息转到: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你需要关注:
在您的工程文件里添加这个节点:
<PreserveCompilationContext>true</PreserveCompilationContext>
了解wiki中反解器的概念及使用。
注意命名空间,自动补充命名空间目前尚未支持,需要您手动操作,使用using方法添加。
想尽一切办法拼接字符串,目前符合CSharp7.3或以下C#版本的都行。
编译模式有区分:StreamComplier内存流编译/FileComplier文件流编译, 文件流编译的内容,可以被动态调用。当你想动态编译类B的时候使用类A,那类A就需要使用文件流编译,相当于dll动态加载到运行时。
使用Natasha中的Operator来构建你的动态内容。
四、性能
这几年随着.NET架构引擎的不断升级,dynamic、emit执行性能已经得到了大幅度提升,roslyn也不例外,之前官方给过性能测试截图,上面显示是比emit快一点,个人的基准测试要等下一个benchmark版本,从耗时的角度来说roslyn <= emit (roslyn有指定release模式编译),所以大家根本不用关心性能问题。
五、使用案例
基于roslyn的动态编译库Natasha的更多相关文章
- 基于 Roslyn 实现动态编译
基于 Roslyn 实现动态编译 Intro 之前做的一个数据库小工具可以支持根据 Model 代码文件生成创建表的 sql 语句,原来是基于 CodeDom 实现的,最近改成使用基于 Roslyn ...
- 动态编译库 Natasha 5.0 兼容版本发布
Natasha 5.0 版本已于 2022/10/10 日发布, 此次大版本更迭带来了兼容性支持, 目前 Natasha 可以兼容 standard2.0 及 coreapp3.1 以上版本. 下载使 ...
- 使用 Roslyn引擎动态编译代码
Roslyn引擎自2014年开源至今这么久,一直没怎么了解过,虽然VS2015早就集成了它. 以前老一套的动态编译方法在 .NET Core中似乎不再支持了,很多方法都是未实现的.下面就介绍如何在.N ...
- 基于 Roslyn 实现一个简单的条件解析引擎
基于 Roslyn 实现一个简单的条件解析引擎 Intro 最近在做一个勋章的服务,我们想定义一些勋章的获取条件,满足条件之后就给用户颁发一个勋章,定义条件的时候会定义需要哪些参数,参数的类型,获取勋 ...
- Vis.js – 基于浏览器的动态 JavaScript 可视化库
Vis.js 是一个动态的,基于浏览器的可视化库.该库被设计为易于使用,能处理大量的动态数据.该库由以下几部分组成:一是数据集和数据视图,基于灵活的键/值数据集,可以添加,更新和删除项目,订阅数据集变 ...
- Natasha 4.0 探索之路系列(三) 基本的动态编译
Natasha 的设计 动态编译 Roslyn 为开发者提供了动态编译的接口, 允许我们以 C# 代码来编写 Emit 或 表达式树生成的程序集, 但是完成一个编译需要诸多步骤, 用户参与的操作也很多 ...
- gcc 动态编译 动态库路径
gcc 动态编译(共享库) 动态编译的可执行文件需要附带一个的动态链接库,在执行时,需要调用其对应动态链接库中的命令优点:体积小,编译快缺点:依赖性高 代码如下: [root@74-82-173-21 ...
- 基于.net standard 的动态编译实现
在前文[基于.net core 微服务的另类实现]结尾处,提到了如何方便自动的生成微服务的客户端代理,使对于调用方透明,同时将枯燥的东西使用框架集成,以提高使用便捷性.在尝试了基于 Emit 中间语言 ...
- 分享基于.NET动态编译&Newtonsoft.Json封装实现JSON转换器(JsonConverter)原理及JSON操作技巧
看文章标题就知道,本文的主题就是关于JSON,JSON转换器(JsonConverter)具有将C#定义的类源代码直接转换成对应的JSON字符串,以及将JSON字符串转换成对应的C#定义的类源代码,而 ...
随机推荐
- 【LeetCode】寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2. 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n)). 你可以假设 nums1 和 nums2 ...
- Spark之RDD
Spark学习之路Spark之RDD 目录 一.RDD的概述 1.1 什么是RDD? RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数 ...
- vue中webpack的配置理解
当我们需要和后台分离部署的时候,必须配置config/index.js: 用vue-cli 自动构建的目录里面 (环境变量及其基本变量的配置) var path = require('path') ...
- Flask框架入门(一)
Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架. Flask 本身相当于一个内核,其他几乎所有的功能都 ...
- Maven 生命周期的阶段与插件的目标之间的绑定关系
clean 生命周期 clean 生命周期的阶段 插件的目标 pre-clean clean maven-clean-plugin:clean post-clean default 生命周期的内置插件 ...
- MySQL数据库 存储引擎,创建表完整的语法,字段类型,约束条件
1.存储引擎 - 存储引擎是用于根据不同的机制处理不同的数据. - 查看mysql中所有引擎: - show engines; - myisam: 5.5以前老的版本使用的存储引擎 - blackho ...
- 01.JAVA语言基础相关解答
1.首先,第一个问题谈到一个java类文件中真的只能有一个公有类吗?并给出了以下代码.可以看出这个程序里有两个public类: 我进行了不同的调试: ...
- Springboot 项目中 xml文件读取yml 配置文件
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlProp ...
- js判断超过几个字符后显示省略号
- Linux--部署Django项目
简单部署 1.安装虚拟环境virtualenvwrapper,创建虚拟环境目录,进入虚拟环境,我的虚拟环境目录叫venv2 [root@HH ~]# workon venv2 (venv2) [roo ...