基于 Roslyn 实现一个简单的条件解析引擎

基于 Roslyn 实现一个简单的条件解析引擎

Intro

最近在做一个勋章的服务,我们想定义一些勋章的获取条件,满足条件之后就给用户颁发一个勋章,定义条件的时候会定义需要哪些参数,参数的类型,获取勋章的时候会提供所需要的参数,有一些内置的参数,内置的参数解析器(ParamResolver)。

最后基于 Roslyn 的 Script + 动态编译功能实现了一个简单的条件解析引擎。

Condition Eval Demo

条件解析示例:

[Fact]
public async Task EvalTest()
{var condition = "x+y > 10";var variables = JsonConvert.SerializeObject(new[]{new{Name = "x",Type = "int"},new{Name = "y",Type = "int"},});var params1 = new Dictionary<string, object>(){{ "x", 2 },{ "y", 3 }};Assert.False(await ScriptEngine.EvalAsync(condition, variables, params1));var params1_1 = JsonConvert.SerializeObject(params1);Assert.False(await ScriptEngine.EvalAsync(condition, variables, params1_1));var params2 = new{x = 6,y = 5};Assert.True(await ScriptEngine.EvalAsync(condition, variables, params2));
}
[Fact]
public async Task EvalStringTest()
{var condition = "x > y.Length";var variables = JsonConvert.SerializeObject(new[]{new{Name = "x",Type = "int"},new{Name = "y",Type = "string"},});var params1 = new{x = 1,y = "3"};Assert.False(await ScriptEngine.EvalAsync(condition, variables, params1));var params2 = new{x = 6,y = "5211"};Assert.True(await ScriptEngine.EvalAsync(condition, variables, params2));
}
[Fact]
public async Task EvalLinqTest()
{var condition = "list.Any(x=>x>10)";var variables = JsonConvert.SerializeObject(new[]{new{Name = "list",Type = "List<int>"}});var params1 = new{list = new List<int>(){1,2,3,4,5}};Assert.False(await ScriptEngine.EvalAsync(condition, variables, params1));var params2 = new{list = new List<int>(){1,2,3,4,5,10,12}};Assert.True(await ScriptEngine.EvalAsync(condition, variables, params2));
}

实现原理

实现的方式是基于 Roslyn 实现的,核心实现是基于 Roslyn 的 Script 实现的,但是 Roslyn Script 的执行有一些限制,不支持匿名类对象的解析,因此还基于 Roslyn 运行时根据变量信息来动态生成一个类型用于执行脚本解析

var result = await CSharpScript.EvaluateAsync<bool>("1 > 2");

运行时动态生成代码在之前的 DbTool 项目中介绍过,介绍文章 基于 Roslyn 实现动态编译

详细实现细节可以参考代码 https://github.com/WeihanLi/SamplesInPractice/tree/master/ScriptEngine

Memo

程序集加载在 framework 和 core 环境下的差异

实现的时候我们的项目有 dotnetcore 的,还有 netframework 的,这两者加载 dll 的时候略有不同,实现的时候用了一个条件编译,在 dotnet core 环境下和 dotnet framework 分开处理,在 dotnetcore 中使用 AssemblyLoadContext 来加载程序集

#if NETCOREAPPvar assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(dllPath);
#elsevar assembly = Assembly.LoadFile(dllPath);
#endif

程序集要保存到文件

原本打算动态生成的程序集保存的一个 Stream 不保存文件,但是实际测试下来必须要保存到文件才可以,所以在项目根目录下创建了一个临时目录 temp 用来保存动态生成的程序集

Roslyn 动态生成的程序集管理

目前还是比较简单的放在一个 temp 目录下了,总觉得每一个类型生成一个程序集有些浪费,但是好像也没办法修改已有程序集,还没找到比较好的解决方案,如果有好的处理方式,欢迎一起交流

More

Natasha 是一个基于 Roslyn 来实现动态编译,能够让你更方便进行动态操作,有动态编译相关需求的可以关注一下这个项目,后面也想用 Natasha 来优化前面提到的问题

基于roslyn的动态编译库,为您提供高效率、高性能、可追踪的动态构建方案,兼容stanadard2.0, 只需原生C#语法不用Emit。让您的动态方法更加容易编写、跟踪、维护

Reference

  • https://github.com/WeihanLi/SamplesInPractice/tree/master/ScriptEngine

  • https://github.com/dotnet/roslyn/wiki/Scripting-API-Samples

  • https://github.com/dotnetcore/Natasha

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/311018.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[蓝桥杯][算法提高VIP]断案-枚举

题目描述 公安人员审问甲、乙、丙、丁四个嫌疑犯&#xff0c;已确知&#xff0c;这四个人当中仅有一人是偷窃者&#xff0c;还知道这四个人的答话&#xff0c;要么完全诚实&#xff0c;要么完全说谎。在回答公安人员的问话中&#xff1a; 甲说&#xff1a;“乙没有偷&#xff0…

BeetleX之vue-autoui自匹配UI插件

vue-autoui 是一款基于vue和element扩展的一个自动化UI控件&#xff0c;它主要提供两个控件封装分别是auto-form和auto-grid; 通过这两个控件可以完成大多数的信息输入和查询输出的需要.auto-form和auto-grid是通过json来描述展示的结构&#xff0c;在处理上要比写html标签来得…

[蓝桥杯][算法提高VIP]最小乘积(提高型)-排序

题目描述 给两组数&#xff0c;各n个。 请调整每组数的排列顺序&#xff0c;使得两组数据相同下标元素对应相乘&#xff0c;然后相加的和最小。要求程序输出这个最小值。 例如两组数分别为:1 3 -5和-2 4 1 那么对应乘积取和的最小值应为&#xff1a; (-5) * 4 3 * (-2) 1 * …

protobufjs 命令执行_protobufjs简单使用

npm i protobufjs -D添加两个proto文件User.protosyntax "proto3";package login;message PBUser {string uid 1;string pwd 2;int64 age 3;}Login.protosyntax "proto3";package login;import "./User.proto";message LoginReq {PBUser us…

.NET Core开发实战(第27课:定义Entity:区分领域模型的内在逻辑和外在行为)--学习笔记...

27 | 定义Entity&#xff1a;区分领域模型的内在逻辑和外在行为上一节讲到领域模型分为两层一层是抽象层&#xff0c;定义了公共的接口和类另一层就是领域模型的定义层先看一下抽象层的定义1、实体接口 IEntitynamespace GeekTime.Domain {public interface IEntity{object[] G…

洛谷 P1596 [USACO10OCT]Lake Counting S-dfs

题目描述 Due to recent rains, water has pooled in various places in Farmer John’s field, which is represented by a rectangle of N x M (1 < N < 100; 1 < M < 100) squares. Each square contains either water (‘W’) or dry land (’.’). Farmer Jo…

国籍 mysql_国籍表SQL,按首字母升序排序

-- phpMyAdmin SQL Dump-- version phpStudy 2014---- 主机: localhost-- 生成日期: 2015 年 12 月 16 日 14:45-- 服务器版本: 5.5.40-- PHP 版本: 5.3.29SET SQL_MODE"NO_AUTO_VALUE_ON_ZERO";SET time_zone "00:00";;;;;---- 数据库: test---- -------…

Abp vNext发布v2.3!

在全球范围内病毒笼罩的日子里,我们发布了ABP框架v2.3, 这篇文章将说明本次发布新增内容和过去的两周我们做了什么.关于新冠病毒和我们的团队关于冠状病毒的状况我们很难过.在Volosoft的团队,我们有不同国家的远程工作者在自己家里工作.从上周开始,我们已经完全开始在家远程工作…

python可以生成ios应用嘛_用python编写ios应用

自从发现了kivy这个东西,就动了用pyhon写ios程序的念头,因为python确实好写,而且我只会这个,懒得去学object-C..不过具体开始搭环境却折腾了好久,我都快放弃了,不过最后还是搭了出来,分享一些心得吧. 1.首先是mac osx环境,这个用虚拟机就行,网上教程很多 2.接下来就是安装Xcode…

[蓝桥杯][算法提高VIP]质数的后代-质数筛

题目描述 在上一季里&#xff0c;曾提到过质数的孤独&#xff0c;其实从另一个角度看&#xff0c;无情隔膜它们的合数全是质数的后代&#xff0c;因为合数可以由质数相乘结合而得。 如果一个合数由两个质数相乘而得&#xff0c;那么我们就叫它是质数们的直接后代。现在&#xf…

ASP.NET Core 中间件分类

ASP.NET Core 中间件的配置方法可以分为以上三种&#xff0c;对应的Helper方法分别是&#xff1a;Run(), Use(), Map()。Run()&#xff0c;使用Run调用中间件的时候&#xff0c;会直接返回一个响应&#xff0c;所以后续的中间件将不会被执行了。Use()&#xff0c;它会对请求做一…

redis持久化到mysql的方案_redis进阶: 数据持久化

redis是内存数据库&#xff0c;即数据库状态都是存储于内存中&#xff0c;因此&#xff0c;当服务器重启或者断开后&#xff0c;数据便会丢失&#xff1b;为了解决数据丢失问题&#xff0c;便需要将数据从内存保持到磁盘中&#xff0c;这就是redis的数据持久化目前&#xff0c;…

《C++ Primer》7.1.2节练习(部分)

练习7.4: class Person {private:string strName;//姓名string strAddress;//地址 };练习7.5: class Person {private:string strName;string strAddress;public:string getName()const{return strName;}string getAddress() const{return strAddress;} };上述两个函数应该被…

如何创建一个自定义的`ErrorHandlerMiddleware`方法

在本文中&#xff0c;我将讲解如何通过自定义ExceptionHandlerMiddleware&#xff0c;以便在中间件管道中发生错误时创建自定义响应&#xff0c;而不是提供一个“重新执行”管道的路径。作者&#xff1a;依乐祝译文&#xff1a;https://www.cnblogs.com/yilezhu/p/12497937.htm…

《C++ Primer》7.1.3节练习

练习7.6: #include <iostream> using namespace std;Sales_data add(const Sales_data &lhs,const Sales_data &rhs) {Sales_data sum lhs;sum.combine(rhs);return sum; }std::istream &read(std::istream &is ,Sales_data &item) {is>>ite…

mysql or中有空查询慢_MySQL 慢查询日志

1.定义2.相关参数2.开启3.原因4.慢查询日志工具mysqldumpslow1.定义作用:用来记录在MySQL中响应时间超过阀值的语句。2.相关参数mysql> show variables like %slow_query%;------------------------------------------------------------| Variable_name | Value …

从业务需求抽象成模型解决方案

从业务需求调研&#xff0c;通过抽象转换成模型技术方案&#xff0c;本文将对这个过程做个拆解&#xff0c;供大家参考。以下我所说的可能都是错的&#xff0c;只是一家之见&#xff0c;欢迎大家在留言区多提意见和看法&#xff0c;互相共勉。一、订单对象-信息需求公司的运营都…

《C++ Primer》7.1.4节练习

练习7.11: #include <iostream> #include <cstring> using namespace std;class Sales_data {public:Sales_data() default;Sales_data(const std::string &book): bookNo(book) {}Sales_data(const std::string &book, const unsigned num, const doubl…

DotNetCore Web应用程序中的Session管理

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。如译文侵犯您的署名权或版权&#xff0c;请联系小编&#xff0c;小编将在24小时内删除。限于译者的能力有限&#xff0c;个别语句翻译略显生硬&#xff0c;还请见谅。作者简介&#xff1a;Jon&#xff08;Jonathan&#x…

css3是什么 ptml_CSS3

CSS3HTMLCSSJavaScript结构表项交互如何学习&#xff1f;CSS是什么CSS怎么用(快速入门)CSS选择器(重点难点)美化网页(文字、阴影、超链接、列表、渐变...)盒子模型浮动定位网页动画(特效效果)1、初识CSS1.1、什么是CSSCascading Style Sheet(层叠样式表)CSS&#xff1a;表现(美…