【开源】跨语言·跨平台·跨数据库(2) —— 用宝轻量框架设计必读

【开源】跨语言·跨平台·跨数据库 (2)—— 用宝轻量框架设计必读

从“数组返回太土”说起:六个设计原则,看懂真正的跨语言架构

咏方舟-长江支流 2026-07-13


用宝框架

拥抱第一 · 一次书写 · 三端复用

C# / Java / ArkTS 直接使用,不用重写

——跨平台、跨语言,全球第一套轻量级架构范式

为什么敢说“拥抱第一”?

用宝框架是全球第一套同时做到以下三点的轻量级架构:

一解跨平台:基于 .NET Standard 2.0,Windows / Linux / macOS 全系列通吃。同时通过跨语言能力,间接覆盖 Java 生态(Windows/Linux/macOS/任何有JVM的平台)和鸿蒙生态(手机/平板/智慧屏/车机)。

二解跨语言:从设计之初就考虑跨语言。接口、基类、返回结构、命名规范全部语言中立。C# 代码直接复制到 Java 和 ArkTS 中,只改语法符号,不改逻辑结构。不是翻译,是直接复用。

三解是第一:全球第一套“一次书写,三端复用”的轻量级架构。传统跨语言方案(COM/gRPC/Thrift)需要定义接口、各语言分别实现,本质还是各写各的。用宝框架是真正的“C# 写一次,Java 直接用,ArkTS 直接用”,不用翻译器,不用中间层,不用代码生成。

放在“三解是第一”之后、“引子”之前,用引用块或灰色背景强调:


明白了,只转这一句,放在“三解是第一”后面:


你现在用 .NET 写的所有代码——实体、仓储、服务、接口、返回结构——在迁移到 Java 或 ArkTS 时,架构、分层、接口命名、继承关系、泛型约束全部保持不变,只需要按目标语言的语法规则做形式上的转换(比如类型后置、冒号改 implements),而设计意图、业务逻辑、调用链路完全一致。

这个转换是机械的、可自动化的,本质上不需要人手工“翻译”,直接用一个工具就可以完成。

这就是用宝框架“跨语言”的真正含义:不是代码的搬运,是设计的迁移。你的业务知识、架构经验、分层思想,可以在 C# / Java / ArkTS 三端之间无缝复用,不需要重新学习、重新设计、重新积累。

这是全球第一套做到这一点的轻量级架构。


用宝框架架构设计原则

—— 从“数组返回太土”说起


引子:一个“太土了”的争议

有一天,有位程序员看了前端调用WebAPI代码:

/// <summary>/// 调用ProductDemo.Core项目-->用宝轻量框架(UserBaoTech.Foundation)/// 前端CRUD调用示例productdemo.html见https://blog.csdn.net/flygoldfish/article/details/162789093/// 开源文档及下载 www.userbao.com 及 GitHub、https://blog.csdn.net/flygoldfish/// </summary>[ApiController][Route("api/[controller]")]publicclassProductController:ControllerBase{[HttpGet]publicasyncTask<MessageResult<Product>>GetList([FromQuery]ProductQueryquery){varrequest=newGetProductListRequest{Query=query};returnawait_getListService.ExecuteAsync(request);}}}

然后单步跟进去用宝框架的代码,看到上面代码中的 MessageResult 当它返回分页数据时,Rows 字段的类型就是 T[](在这里是 Product[])。他说怎么不用 List ,你这也太土了吧?

“你这也太土了吧,返回数据居然用T[]数组?现在谁不用List<T>啊?”

他没说错,在 C# 里,List<T>确实更常用、更“现代”。但用宝框架选择T[],不是因为写代码的人水平不行,而是因为——

用宝框架的代码是要直接复制到 Java 和鸿蒙 ArkTS 里用的。

T[]在 C#、Java、ArkTS 中都是原生语法,不需要额外引入任何命名空间或类库。如果用了List<T>,Java 那边得换成ArrayList<T>,ArkTS 那边得换成Array<T>,代码就“变形”了。

所以,不是用宝框架太土,是提问的人没看懂它要跨什么。

这就是用宝框架的第一个设计原则:跨语言一致性。

原则一:跨语言一致性

用宝框架的定位,不是“又一个 C# 框架”,而是一套可以在 C#、Java、ArkTS 之间直接复制的架构范式

具体做法:

  • 接口命名统一:IEntity<TKey>IRepository<T>IService<TParam, TResult>
  • 基类命名统一:RepositoryBase<T>ServiceBase<TParam, TResult>KeyServiceBase<TResult>
  • 返回结构统一:MessageResult<T>
  • 数据类型统一:T[]而不是List<T>Dictionary<string, object>而不是IDictionary的特定实现

效果:用宝框架的 C# 代码,可以直接复制到 ArkTS 项目中,稍作语法调整即可运行;复制到 Java 项目中,只需要把特性([Table])换成注解(@Table),底层逻辑完全一致。

这不是“翻译”,是“直接复用”。

原则二:轻量化

用宝框架不追新、不堆砌、不依赖。

核心类库UserBaoTech.Foundation的目标框架是.NET Standard 2.0,唯一的 NuGet 引用是System.Text.Json。没有 EF、没有 Dapper、没有 AutoMapper,没有任何重量级依赖。

为什么这么轻?

  • .NET Standard 2.0是 .NET 世界里最后一份“通用契约”,.NET Framework 4.8、.NET Core 3.1、.NET 6/8/10 都能引用它,永不淘汰
  • 不用 ORM,手写 SQL,因为 SQL 本身是跨语言标准,在 Java 和 ArkTS 里也能执行
  • 唯一的 JSON 库是为了序列化,JSON 也是跨语言标准

轻量,是为了让用宝框架不绑定任何特定平台或版本。你现在写的代码,十年后还能用。

原则三:开放式 / 可插拔设计

用宝框架的核心组件全部基于接口,而不是具体实现。

组件接口默认实现可替换为
日志ILoggerNullLoggerSerilog、NLog、自定义
缓存ICacheProviderNullCacheProviderRedis、MemoryCache、自定义
配置IConfigProviderMemoryConfigProviderJSON文件、数据库、环境变量
数据访问IDataAccessExecutorDataAccessExecutor自定义执行器

效果:你不想用日志,就保持NullLogger;你想用 Redis,就实现ICacheProvider并注册;你想换数据库,就改连接字符串,业务代码一行不改。

这是“插拔式”设计,不是“写死式”设计。

原则四:单一职责原则

用宝框架的业务服务层,每个 Service 只做一件事。

Service职责
GetProductListService只负责查询列表
CreateProductService只负责新增
UpdateProductService只负责更新
GetProductByIdKeyService只负责按主键查询
DeleteProductKeyService只负责删除

为什么拆这么细?

  • 改了查询逻辑,不会影响到删除逻辑
  • 新增一个过滤条件,只需要改对应的查询 Service
  • 每个 Service 的代码量很小,容易理解、容易测试
  • 团队协作时,两个人不会改到同一个文件

这是“拆开以隔离变化”,不是“为了拆而拆”。

原则五:实体与查询参数分离

用宝框架把“数据库表结构”和“前端查询条件”分成了两个不同的概念。

  • 实体(Entity):对应数据库表,包含所有字段(包括内部字段、敏感字段)
  • 查询参数(Query):对应前端传入的过滤条件,只包含前端关心的字段
// 实体:对应数据库表,包含所有字段publicclassProduct:IEntity<string>{publicstringId{get;set;}publicstringName{get;set;}publicdecimalPrice{get;set;}publicintStock{get;set;}publicstringInternalCode{get;set;}// 内部字段,不对外publicDateTimeCreatedAt{get;set;}publicDateTimeUpdatedAt{get;set;}publicboolIsDeleted{get;set;}}// 查询参数:前端传入的过滤条件publicclassProductQuery:QueryParametersBase{publicstringName{get;set;}// 前端只关心名称搜索publicdecimal?MinPrice{get;set;}// 前端只关心价格范围publicdecimal?MaxPrice{get;set;}}

好处

  • 数据库表加了新字段,不影响查询参数
  • 查询参数加了新条件,不影响实体
  • 前端只传它需要的字段,不关心数据库内部结构

原则六:返回模型与实体分离

用宝框架不直接把实体返回给前端,而是通过MessageResult<T>和 DTO 进行隔离。

为什么?

  • 数据库里有密码字段,返回时屏蔽掉
  • 数据库里有内部状态码(如012),返回时翻译成前端能看懂的中文
  • 数据库表有 20 个字段,前端只关心 3 个,只返回那 3 个
// 实体:存了密码publicclassUser:IEntity<string>{publicstringId{get;set;}publicstringUserName{get;set;}publicstringPasswordHash{get;set;}// 不能返回给前端publicintRoleCode{get;set;}// 内部状态码}// 返回模型:只返回前端需要的字段publicclassUserDto{publicstringId{get;set;}publicstringUserName{get;set;}publicstringRoleName{get;set;}// 翻译后的中文}

好处

  • 不暴露内部存储细节
  • 前端只收到它需要的数据
  • 实体变化时,只要返回模型不变,前端不受影响

原则七:AI可扩展性

用宝轻量框架不只是为“人”设计的,也是为“AI”设计的。
可扩展性不只体现在接口的可插拔、组件的可替换,还体现在配置的标准化和模板的通用化。SQL 是标准查询语言,JSON 是标准数据格式,XML 是标准结构描述,HTML 是标准展示模板——而这四种标准,恰好都是 AI 天然擅长生成和处理的内容。
金质打印通是作者的开源作品之一,而它的姊妹篇“天下报表”早在 2006年就采用 XML 做报表配置。如今这套报表引擎已整合进用宝框架,成为其上层能力的重要验证案例。
用宝框架的设计,本质上是在为 AI 参与软件工程提供一套清晰的边界和规范。框架负责定义“怎么写”,AI 负责生成“写什么”。开发者只需要描述业务需求,AI 就能按框架规范生成符合标准的代码、配置和模板。
这套轻量级架构,非常契合中小企业快速开发、灵活迭代、AI 辅助编程的实际需求。

你说得对,我之前的表述确实不准确。用宝框架本身就是多层架构,天然支持微服务

productdemo.html通过 WebAPI 调用后端,后端 Controller → Service → Repository 分层清晰,每个服务独立部署、独立运行,本身就是微服务架构的一种实现形态。

所以原则八的表述应该修正为:


原则八:局限性

用宝框架的定位是轻量、标准、可迁移,主战场是中小企业标准化业务系统

用宝框架本身就是多层架构,天然支持微服务——Controller 层、Service 层、Repository 层边界清晰,每个服务可以独立拆分、独立部署。productdemo.html示例通过 WebAPI 调用后端的模式,本身就是一种微服务实现。

用宝框架的局限,主要体现在高并发、集群、分布式事务这类大规模场景——这些场景对连接池、缓存、消息队列、分布式一致性有更高的要求,而这些不是用宝框架当前要解决的问题,需要由上层扩展来补充。

但架构本身支持微服务,这一点没有问题。

用宝框架只做一件事——把“中小企业的常规业务开发”这件事,做得足够轻、足够稳、足够可迁移,同时为微服务提供清晰的分层基础。

机关枪可以打很多仗,但如果你非要拿它去打航母,那是你选错了武器。用宝框架清楚自己的边界——它解决的是中小企业 80% 的常规业务场景,剩下的 20%,留给真正需要它的场景去扩展。

期待中的AI自然人报表

金质打印通从2003年开发并开源,以及它的姊妹篇 天下报表 应用 XML 配置报表,现在开始移植到用宝框架,将用宝框架开源、天下报表也将开源。金质打印通当初说的是**“金质打印通,通打开下报表”,那天下报表,让天下人直接口述出报表**。因为AI最擅长结构化语言,更适用于自然人直接描述想要的报表。因为AI最擅长XML、SQL、Html这些最通用的语言。

以下是部分设计QA

亮点一:MessageResult 的泛型设计

publicclassMessageResult<T>:MessageResult{publicTData{get;set;}// 非分页数据publicintTotal{get;set;}// 分页总记录数publicT[]Rows{get;set;}// 分页数据列表}

设计要点

  • 分页与非分页不混用:分页只填Rows+Total,非分页只填Data
  • 泛型让返回类型灵活:MessageResult<Product>返回产品,MessageResult<string>返回新增 ID
  • 前端只认五个字段:successmessagedatarowstotal,所有接口都一样

为什么不用List<T>前面已经说过了——为了跨语言一致性。

亮点二:IEntity 的泛型设计

publicinterfaceIEntity<TKey>{TKeyId{get;set;}DateTimeCreatedAt{get;set;}DateTimeUpdatedAt{get;set;}boolIsDeleted{get;set;}}

为什么用泛型?

  • 大部分表用string(GUID),但旧系统可能需要int(自增ID)
  • 泛型让主键类型灵活,不绑死任何一种
  • CreatedAtUpdatedAtIsDeleted是所有实体都有的公共字段,抽到接口里不重复定义

亮点三:KeyRequest 消灭重复 DTO

publicclassKeyRequest{publicstringId{get;set;}}

问题:每个实体都有按主键查询和按主键删除的需求,如果每个都定义一个 DTO:

publicclassGetProductByIdRequest{publicstringId{get;set;}}publicclassDeleteProductByIdRequest{publicstringId{get;set;}}publicclassGetUserByIdRequest{publicstringId{get;set;}}// ... 无穷无尽

用宝框架的解决方案:直接用KeyRequest,配合KeyServiceBase

publicclassGetProductByIdKeyService:KeyServiceBase<MessageResult<Product>>{protectedoverrideasyncTask<MessageResult<Product>>DoExecuteAsync(stringid){// 业务逻辑}}

效果:不需要为每个实体定义“按主键查询”和“按主键删除”的 DTO,一个KeyRequest通吃。

亮点四:数据库提供者(方言适配)

用宝框架的DataAccessExecutor内部,通过DatabaseType枚举统一处理不同数据库的差异:

  • 参数前缀:SQL Server/MySQL 用@,Oracle 用:,ODBC 用?
  • 分页 SQL:SQL Server 用OFFSET FETCH,MySQL 用LIMIT,Oracle 用ROWNUM
  • 自增 ID 回读:SQL Server 用SCOPE_IDENTITY(),MySQL 用LAST_INSERT_ID()
  • 日期格式化:Oracle 需TO_DATE,其他数据库直接用字符串

当前采用 switch 集中处理主流数据库方言,后续准备改为提供者(Provider)模式,支持用户自定义扩展,同时保留默认实现,确保开箱即用。

效果

  • 业务层写的是标准 SQL,完全感知不到数据库差异
  • 切换数据库时,只改连接字符串,业务代码一行不改
  • 新增数据库支持时,只需在DataAccessExecutor中增加分支

这个设计不是“写死”,是“集中处理”。所有方言逻辑在一个地方,上层干干净净。

亮点五:依赖注入传连接,不自己建连接

// Program.csvarconnectionString=builder.Configuration.GetConnectionString("Default");builder.Services.AddScoped<IDbConnection>(sp=>newMySqlConnection(connectionString));builder.Services.AddScoped<IDataAccessExecutor>(sp=>{varconn=sp.GetRequiredService<IDbConnection>();varlogger=sp.GetRequiredService<ILogger>();returnnewDataAccessExecutor(conn,DatabaseType.MySql,logger);});

为什么这样设计?

  • 用宝框架不负责连接的生命周期,连接由上层应用管理
  • 上层可能已经建好了连接,或者需要复用已有连接
  • 用宝框架只要求传入一个IDbConnection,不关心它怎么来的
  • 这样框架能适配任何已经存在的系统,而不是要求别人按你的方式建连接

这是“依赖注入”的正解——框架不替你做决定,只负责执行。

结语

用宝框架不是一个“炫技”的框架。

它没有用最新的 .NET 语法,没有用最酷的设计模式,没有引入任何时髦的第三方库。它做的唯一一件事,就是把 20 年经验中沉淀下来的、最稳定的设计原则,固化成了一套可复用的代码结构

它的设计原则可以总结为:

  1. 跨语言一致性:C# 写的代码,可以直接在 Java 和 ArkTS 里用
  2. 轻量化:零依赖,永不淘汰
  3. 开放式设计:所有组件可插拔、可替换
  4. 单一职责:每个类只做一件事
  5. 实体与查询分离:前端参数与数据库表互不干扰
  6. 返回模型与实体分离:不暴露内部存储细节

所以,下次有人看到用宝框架返回T[]说“太土了”,你可以告诉他:

“不是太土了,是你看不懂它的设计意图。”

用宝框架的设计,不是为了迎合某一种语言的“时尚”,而是为了跨越语言、跨越平台、跨越时间

这才是它真正有价值的地方。

版本:第一版
发布日期:2026年7月13日
作者:周方勇/咏方舟-长江支流(金质打印通、用宝框架开源作者)
适用范围:所有基于 UserBaoTech.Foundation 的新项目开发

反馈与交流:欢迎在评论区留言或私信交流。如果你正在寻找一套不用 EF、不用 Dapper、可跨语言迁移的轻量级基架,用宝框架或许是一个值得尝试的选择。


用宝框架,拥抱第一 · 一次书写 · 三端复用——不仅是用户的朋友,而且是用户的宝贝