近日,一项旨在为.NET开发者提供原生C#实现的通用表达式语言(Common Expression Language,简称CEL)引擎的开源项目引发了技术社区的广泛关注。该项目由资深.NET开发者主导,目标是打造一个纯C#编写、无外部依赖的CEL解析与求值器,从而让.NET开发者能够以更低的性能开销、更高的类型安全性在应用程序中嵌入策略规则、数据过滤、动态配置等场景所需的表达式计算能力。
CEL引擎:从Kubernetes到云原生
CEL最初由Google为Kubernetes项目设计,是一种轻量级、类型安全的表达式语言,专用于策略评估和规则匹配。它不同于通用的脚本语言(如JavaScript或Python),CEL被刻意设计为“非图灵完备”,强调可沙箱化、可静态分析和可高效求值。如今,CEL已被广泛用于Istio、Knative、API Gateway等云原生组件中,用于定义授权策略、流量路由规则、资源配额校验等。
然而,长期以来,.NET生态中缺乏一个原生的、高性能的CEL引擎。开发者若要在C#应用中集成CEL,通常不得不借助P/Invoke调用C++实现的Re2或cel-go库,或者依赖ProtoBuf进行函数映射,这不仅增加了部署复杂性,还带来了跨平台兼容性和垃圾回收(GC)压力。而直接使用JavaScript引擎(如V8嵌入)则更显得“杀鸡用牛刀”。
原生C#实现:性能与集成的双重突破
新发布的C# CEL引擎(暂称“CelCS”)采用完全托管代码实现,基于System.Linq.Expressions和Antlr4语法分析器构建,同时提供了可选的AOT编译路径。其核心设计目标有三个:
- 解析与编译分离:将CEL表达式文本解析为抽象语法树(AST),然后编译为可重用的委托(Delegate),避免反复解析带来的开销。
- 类型安全:利用C#强类型特性,在编译时即进行类型检查,而非在运行时抛出异常。项目为CEL标准库中的字符串、数字、时间、列表、映射等类型提供了对应的C#原生包装。
- 零外部依赖:运行时无需Go运行时、Protobuf或任何原生库,仅依赖.NET基础类库,非常适合AOT部署、iOS/Android等受限环境。
在性能测试中,CelCS对典型策略表达式(如“request.path.startsWith(‘/api’)”和“user.role in [‘admin’, ‘editor’]”的组合)的求值速度,在热路径上比通过gRPC调用CEL-Go服务快10倍,比基于解释器的Python CEL实现快50倍以上。更重要的是,由于全部是托管代码,GC压力远低于脚本桥接方案。
与.NET深度集成:表达现实世界的规则
CelCS不仅实现了CEL标准语义,还针对.NET生态进行了扩展。它支持直接访问C#对象的属性与方法,并允许开发者注册自定义函数和变量解析器。例如,在ASP.NET Core应用中,可以这样使用:
var rule = CelEngine.Compile("user.Age >= 18 && user.Country in ['CN', 'US']");
var result = rule.Evaluate(new { User = new { Age = 22, Country = "CN" } });
这种模式使得安全策略、AB测试分流、动态表单校验等场景的代码量大幅减少,同时逻辑与业务代码解耦。
社区反响与未来展望
项目在GitHub开源后,迅速获得了超过500星标,并在Hacker News和Reddit的dotnet板块引发了热烈讨论。微软MVP、.NET性能优化专家Maarten Balliauw评论道:“这是一个填补生态空白的重要尝试。cel-go的性能瓶颈在.NET世界里一直是个痛点,CelCS用纯托管代码解决了它。”
目前该项目仍处于beta阶段,计划在下一个版本中支持自定义宏、完整的Protocol Buffers元数据绑定以及更细粒度的权限沙箱。随着.NET 9对Native AOT的进一步优化,CelCS有望成为云原生.NET应用的首选规则引擎。
对于需要在.NET中实现高效、安全、可移植的表达式评估的开发者而言,这个原生的C# CEL引擎,或许正是等待已久的答案。