将 Zod 移植到 C#:ZodSharp – 零分配、高性能的 .NET 模式验证库

发布: (2025年12月14日 GMT+8 08:05)
7 min read
原文: Dev.to

Source: Dev.to

介绍

作为一名 .NET 开发者,我长期受到一个顽固痛点的困扰:大多数验证库高度依赖反射,导致性能缓慢且持续产生内存分配。无论是验证 API 输入、表单还是数据管道,这些开销都会累积——尤其在高吞吐场景下更为明显。

后来我发现了 Zod —— TypeScript 世界中由 colinhacks 创建的模式验证黄金标准。它流畅的 API、完整的类型推断、优秀的错误信息以及零依赖设计简直像魔法。但在 C# 中并没有类似的东西。

于是我构建了 ZodSharp —— 为现代 .NET 从零重写的完整实现,始终聚焦于 性能、零分配和开发者体验

为什么 Zod 成为 TypeScript 的标准

  • 流畅、可链式调用的 API,书写起来令人愉悦
  • 自动推断的完整类型安全
  • 强大的组合能力,支持复杂模式
  • 丰富的转换和细化功能
  • 清晰、结构化的错误报告
  • 零运行时依赖

在 .NET 中,我们有 FluentValidation 等可靠选项,但它们依赖反射和表达式树——灵活性很好,却在性能关键路径上代价高昂。ZodSharp 将同样优雅的开发者体验带到 C# —— 没有分配开销

这不是简单的移植 —— 以性能为首的重写

在忠实于 Zod 公共 API 与语义的同时,几乎所有内部细节都为 .NET 的优势重新设计。

零分配:核心设计目标

首要目标:在热点路径中验证应产生 零垃圾。基于反射的验证在每次调用时都会创建对象、闭包和临时集合。ZodSharp 完全消除了这些。

关键技术

  • 验证规则作为结构体
public readonly struct MinLengthRule : IValidationRule
{
    private readonly int _min;
    public MinLengthRule(int min) => _min = min;

    public bool IsValid(in string value) => value.Length >= _min;
}
  • 使用开销极小的不可变集合(ImmutableArrayImmutableDictionary
  • ValidationResult 作为结构体 —— 成功或失败时不在堆上分配
  • ArrayPool 用于任何临时缓冲区
  • 在性能关键段使用手动循环而非 LINQ
  • SpanReadOnlySpan 用于零拷贝的字符串操作

流畅 API —— 尽可能贴近 Zod

API 让 Zod 用户立刻感到熟悉:

// 几乎与 Zod TS 完全相同
var schema = Z.String()
    .Min(3)
    .Max(50)
    .Email()
    .Trim()
    .ToLower();

对象模式:

var userSchema = Z.Object()
    .Field("name", Z.String().Min(1))
    .Field("age", Z.Number().Min(0).Max(120))
    .Field("email", Z.String().Email())
    .Build();

转换、细化、联合、可选、字面量 —— 全部支持。

源生成器与 DataAnnotations 集成

.NET 特有的最大收益之一:编译时模式生成

[ZodSchema]
public class User
{
    [Required, StringLength(50, MinimumLength = 3)]
    public string Name { get; set; } = string.Empty;

    [Range(0, 120)]
    public int Age { get; set; }

    [EmailAddress]
    public string Email { get; set; } = string.Empty;
}

// 使用方式
var result = UserSchema.Validate(new User { /* ... */ });

无需运行时反射。

项目架构概览

ZodSharp/
├── src/ZodSharp/
│   ├── Core/                → Interfaces, base classes, results, errors
│   ├── Schemas/             → String, Number, Object, Array, Union, etc.
│   ├── Rules/               → Struct‑based validation rules
│   ├── Expressions/         → Compiled validators via Expression Trees
│   ├── Json/                → Newtonsoft.Json integration
│   ├── Optimizations/       → Zero‑allocation helpers
│   └── Z.cs                 → Static factory (Z.String(), Z.Object(), etc.)
├── src/ZodSharp.SourceGenerators/
│   └── ZodSchemaGenerator.cs → [ZodSchema] source generator
├── example/                 → Full usage samples
└── README.md

大致的性能提升

早期基准显示相较于典型的基于反射的验证,提升幅度惊人:

场景基于反射ZodSharp增益
简单字符串验证~0.15 ms~0.01 ms~15 倍更快
复杂对象验证~0.8 ms~0.05 ms~16 倍更快
每次验证的分配多次已消除

在负载增大时差距进一步拉大。

实际使用场景

ZodSharp 在任何需要验证性能的地方都大放异彩:

  • 高吞吐量的 API(REST、gRPC、GraphQL)
  • 频繁输入验证的微服务
  • 实时系统
  • 数据摄取管道
  • 具有复杂表单的桌面/移动应用
  • 任何想要拥有 Zod‑式开发体验却不想承担运行时成本的场景

已实现的功能

  • 流畅的模式构建
  • 完整的原始类型支持(string、number、boolean、array、object、union、literal)
  • 转换(.Trim().ToLower() 等)
  • 细化(自定义验证)
  • 可选 / 可空包装器
  • 判别式联合
  • 延迟/递归模式
  • 带 DataAnnotations 的源生成器
  • Newtonsoft.Json 集成
  • 高级字符串规则(.Url().Uuid().Email().StartsWith() …)
  • 高级数字规则(.Positive().MultipleOf().Finite() …)

接下来计划

  • 公共基准套件
  • ASP.NET Core 模型绑定集成
  • Entity Framework 验证钩子
  • 更多 JSON 序列化支持(System.Text.Json
  • 增强的错误格式化
  • 社区贡献

最后思考

构建 ZodSharp 的过程令人极度满足。它不仅仅是把 Zod 带到 C#——更是为 .NET 生态系统中一个真实且广泛的痛点提供了解决方案:快速、类型安全、零开销的验证

如果你曾为反射导致的慢速而叹气,或渴望在 C# 中拥有更现代的验证体验,快去试试 ZodSharp 吧。欢迎提供反馈、点星、提交 issue 与 PR!

感谢阅读! 🚀

Back to Blog

相关文章

阅读更多 »