RLei.RulesJint 1.0.2

dotnet add package RLei.RulesJint --version 1.0.2
                    
NuGet\Install-Package RLei.RulesJint -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RLei.RulesJint" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RLei.RulesJint" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="RLei.RulesJint" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RLei.RulesJint --version 1.0.2
                    
#r "nuget: RLei.RulesJint, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RLei.RulesJint@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RLei.RulesJint&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=RLei.RulesJint&version=1.0.2
                    
Install as a Cake Tool

Rules.Jint

一个基于 Jint(.NET 的 JavaScript 解释器)封装的规则引擎库,支持表达式缓存、异步求值和 55 个全局 JS 辅助函数。

功能特性

  • 表达式预编译缓存 — 基于 ConcurrentDictionary 缓存 Prepared<Script>,避免重复解析
  • 输入变量自动小写化 — 所有 JObject 的属性名在注入引擎时自动转为小写
  • 55 个全局辅助函数 — 涵盖类型转换、字符串操作、数学运算、日期时间、集合操作、条件判断、属性检测、工具函数
  • 异步求值 — 提供 EvaluateExpressionAsync 一个异步 API

快速开始

using Newtonsoft.Json.Linq;
using Rules.Jint;

var factory = new JintEngineFactory();

var expression = "iif(age >= 18, '成人', '未成年')";
var inputs = JObject.FromObject(new { age = 20 });

var result = await factory.EvaluateExpressionAsync(expression, inputs);
Console.WriteLine(result.Result); // 输出: 成人

字符串字面量 vs 变量引用

表达式中的字符串有两种含义,取决于是否使用引号:

写法 类型 说明 示例 结果
'name' 字面量 原始字符串值 str('name') "name"
name 变量引用 从上下文中查找变量并求值 str(name) 变量 name 的值,如 "Alice"
'user.age' 字面量 原始字符串(含点号) hasProperty('user.age') 查根上下文是否有键 user.age
user.age 属性访问 变量 user 的 age 属性 str(user.age) 变量 user 的 age 值

核心原则:

  • 引号 → 字符串就是它本身,不会被解析
  • 无引号 → Jint 将其视为变量名/表达式,从引擎上下文中求值

如何快速识别

  1. 查找引号 → 字符串字面量

    // 变量引用的具体值
    var inputs = JObject.FromObject(new { name = "Alice" });
    await Eval("str(name)");     // "Alice"
    
    // 字面量字符串,固定不变
    await Eval("str('name')");   // "name"(与上下文无关,始终返回字面字符串)
    
  2. 无引号表示变量引用

    // 变量引用,可从上下文中获取值
    var inputs = JObject.FromObject(new { user = new { name = "Alice" } });
    await Eval("str(user.name)");  // "Alice"
    
    // 字面量字符串,完全保留原值
    await Eval("str('user.name')");  // "user.name"(不解析点号表示法)
    

实际应用

属性检测示例:
// 字面量用法:检查键名是否存在,而非检查值的存在性
var inputs = JObject.FromObject(new { user = new { name = "Alice", age = 30 } });
await Eval("hasProperty('user.name')", inputs);   // true - 检查是否存在 key 'user.name'
await Eval("hasProperty(user, 'name')", inputs); // true - 检查 user 对象是否存在属性 'name'
字符串操作示例:
// 字面量字符串保持原值
await Eval("str('fixed-string')");   // "fixed-string"(与上下文无关)

// 变量引用从上下文中获取值
await Eval("str(fullName)");         // 获取 fullName 变量的实际值

API

核心类

类型 说明
JintEngineFactory 引擎工厂,提供表达式缓存与异步求值
EvaluateRequest 请求记录:Expression + Inputs
ExpressionEvaluateResult 求值结果:Success、ErrorMessage、Result

JintEngineFactory

// 创建带输入的引擎
Engine CreateEngine(JObject inputs)

// 异步求值(自动缓存表达式)
Task<ExpressionEvaluateResult> EvaluateExpressionAsync(string expression, JObject inputs)

EvaluateRequest

public record EvaluateRequest(string Expression, JObject Inputs);

ExpressionEvaluateResult

属性 类型 说明
Success bool 求值是否成功
ErrorMessage string? 异常时的错误消息
Result object? 求值结果

全局辅助函数

所有函数名均为 小写开头驼峰 风格,可在 JS 表达式中直接调用。

类型转换

函数 签名 说明
int (val) => int 转 Int32
float (val) => double 转 Double
str (val) => string 转字符串
bool (val) => bool 转 Boolean
decimal (val) => decimal 转 Decimal

字符串函数

函数 签名 说明
toUpperCase (s) => string 转大写
toLowerCase (s) => string 转小写
trim (s) => string 去除首尾空白
contains (s, substr) => bool 是否包含子串
startsWith (s, prefix) => bool 是否以指定字符串开头
endsWith (s, suffix) => bool 是否以指定字符串结尾
substring (s, start, length) => string 截取子串
length (s) => int 字符串长度
replaceAll (s, oldVal, newVal) => string 全局替换
concat (a, b) => string 字符串拼接

数学函数

函数 签名 说明
abs (x) => double 绝对值
round (x) => double 四舍五入
floor (x) => double 向下取整
ceil (x) => double 向上取整
max (a, b) => double 返回较大值
min (a, b) => double 返回较小值
pow (x, y) => double 幂运算
sqrt (x) => double 平方根

日期时间函数(16 个)

函数 签名 说明
now (format?) => object 当前本地时间
utcNow (format?) => object 当前 UTC 时间
today (format?) => object 今日日期
parseDate (str, format?) => object 解析日期字符串
formatDate (dt, format) => string 格式化日期
dateDiff (d1, d2) => double 日期差(天数)
addDays (dt, days) => DateTime 添加天数
addMonths (dt, months) => DateTime 添加月数
addYears (dt, years) => DateTime 添加年数
year (dt) => int 获取年份
month (dt) => int 获取月份
day (dt) => int 获取日
dayOfWeek (dt) => int 获取星期几 (0=Sunday)
hour (dt) => int 获取小时
minute (dt) => int 获取分钟
second (dt) => int 获取秒

集合函数

函数 签名 说明
isArray (obj) => bool 是否为数组
count (arr) => int 数组元素个数
arrayContains (arr, val) => bool 数组是否包含指定值
isEmpty (arr) => bool 数组是否为空
first (arr) => object? 第一个元素
last (arr) => object? 最后一个元素

条件函数

函数 签名 说明
isNull (obj) => bool 是否为 null 或 DBNull
isNullOrEmpty (obj) => bool 是否为 null 或空字符串
isNullOrWhiteSpace (obj) => bool 是否为 null 或空白字符串
coalesce (val, default) => object 返回第一个非 null 值(注:Jint 中会始终执行第二个参数)
iif (cond, trueVal, falseVal) => object 三元条件

属性检测

用于检测对象属性和变量值的函数。

hasProperty — 属性存在检查

// 用法一:检查根上下文中是否存在属性
hasProperty('name')                    // true / false
hasProperty('user.address.city')       // 支持点号分隔的嵌套路径

// 用法二:检查指定对象是否存在属性
hasProperty(obj, 'name')               // 指定对象
hasProperty(user, 'address.city')      // 指定对象 + 嵌套路径
调用方式 说明 示例
hasProperty('key') 检查根上下文是否存在 key hasProperty('age')
hasProperty('parent.child') 嵌套路径检查,逐层查找 hasProperty('user.address.city')
hasProperty(obj, 'key') 检查指定对象是否存在 key hasProperty(user, 'name')
hasProperty(obj, 'parent.child') 指定对象 + 嵌套路径 hasProperty(user, 'address.city')

嵌套路径规则: 按 . 分隔逐层查找,中间任一节点缺失立即返回 false,不会抛出异常。

// 输入: { user: { name: "Alice", address: { city: "Beijing" } } }
hasProperty('user.name')                // true
hasProperty('user.address.city')        // true
hasProperty('user.address.zip')         // false (zip 不存在)
hasProperty('user.nonexistent')         // false (nonexistent 不存在)

hasValue — 值是否存在

检查值是否为非 null、非 DBNull、非空白字符串。

签名 说明
(value) => bool 值是否存在
hasValue(name)           // 变量 name 是否有值
hasValue(user.name)      // 嵌套属性是否有值

isNotNull — 非 null 检查

检查值是否为非 null、非 DBNull。

签名 说明
(value) => bool 是否为非 null/非 DBNull
isNotNull(name)          // 变量 name 是否非 null
isNotNull(user)          // 变量 user 是否非 null

注意: hasValue 和 isNotNull 接收的是已求值的变量,而非字符串属性名。如果要检查上下文中的某个属性值,请使用不带引号的变量引用:

// ✓ 正确:变量引用,检查 age 的值
hasValue(age)

// ✗ 错误:字符串字面量,只检查字符串 "age" 本身
hasValue('age')

工具函数

函数 签名 说明
guid () => string 生成新 GUID
getType (obj) => string 获取类型名称

输入变量

JObject 的属性名会自动转为 小写 注入引擎,因此在表达式中应使用小写变量名。

var inputs = JObject.FromObject(new { UserName = "Alice", Age = 30 });
// 在表达式中使用: username、age
var result = await factory.EvaluateExpressionAsync("concat('Hello, ', username) + ' age: ' + str(age)", inputs);

嵌套变量

JObject 的嵌套对象会自动转为平铺的字典结构,可以通过 . 操作符访问:

var inputs = JObject.FromObject(new
{
    user = new { name = "Alice", address = new { city = "Beijing" } }
});

// 在表达式中使用:
//   user.name          → "Alice"
//   user.address.city  → "Beijing"
var result = await factory.EvaluateExpressionAsync("user.address.city === 'Beijing'", inputs);

完整示例

属性检测与条件判断

var inputs = JObject.FromObject(new
{
    user = new { name = "  Alice  ", age = 25, roles = new[] { "admin", "user" } }
});

var expression = @"
    hasProperty(user, 'name') &&       // 对象是否存在 name 属性
    hasValue(user.name) &&             // 值是否非空
    str(toLowerCase(trim(user.name))) === 'alice' &&  // 字符串处理
    user.age >= 18 &&                  // 数字比较
    arrayContains(user.roles, 'admin') // 集合包含
";
var result = await factory.EvaluateExpressionAsync(expression, inputs);
// result: true

表达式缓存

JintEngineFactory 内部使用 ConcurrentDictionary 缓存已预编译的表达式,重复表达式不会重复解析。

依赖

NuGet

PM> Install-Package RLei.RulesJint

开源协议

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 132 7/2/2026
1.0.1 118 7/1/2026
1.0.0 119 6/24/2026