【开源】跨语言·跨平台·跨数据库(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 也是跨语言标准
轻量,是为了让用宝框架不绑定任何特定平台或版本。你现在写的代码,十年后还能用。
原则三:开放式 / 可插拔设计
用宝框架的核心组件全部基于接口,而不是具体实现。
| 组件 | 接口 | 默认实现 | 可替换为 |
|---|---|---|---|
| 日志 | ILogger | NullLogger | Serilog、NLog、自定义 |
| 缓存 | ICacheProvider | NullCacheProvider | Redis、MemoryCache、自定义 |
| 配置 | IConfigProvider | MemoryConfigProvider | JSON文件、数据库、环境变量 |
| 数据访问 | IDataAccessExecutor | DataAccessExecutor | 自定义执行器 |
效果:你不想用日志,就保持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 进行隔离。
为什么?
- 数据库里有密码字段,返回时屏蔽掉
- 数据库里有内部状态码(如
0、1、2),返回时翻译成前端能看懂的中文 - 数据库表有 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 - 前端只认五个字段:
success、message、data、rows、total,所有接口都一样
为什么不用List<T>?前面已经说过了——为了跨语言一致性。
亮点二:IEntity 的泛型设计
publicinterfaceIEntity<TKey>{TKeyId{get;set;}DateTimeCreatedAt{get;set;}DateTimeUpdatedAt{get;set;}boolIsDeleted{get;set;}}为什么用泛型?
- 大部分表用
string(GUID),但旧系统可能需要int(自增ID) - 泛型让主键类型灵活,不绑死任何一种
CreatedAt、UpdatedAt、IsDeleted是所有实体都有的公共字段,抽到接口里不重复定义
亮点三: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 年经验中沉淀下来的、最稳定的设计原则,固化成了一套可复用的代码结构。
它的设计原则可以总结为:
- 跨语言一致性:C# 写的代码,可以直接在 Java 和 ArkTS 里用
- 轻量化:零依赖,永不淘汰
- 开放式设计:所有组件可插拔、可替换
- 单一职责:每个类只做一件事
- 实体与查询分离:前端参数与数据库表互不干扰
- 返回模型与实体分离:不暴露内部存储细节
所以,下次有人看到用宝框架返回T[]说“太土了”,你可以告诉他:
“不是太土了,是你看不懂它的设计意图。”
用宝框架的设计,不是为了迎合某一种语言的“时尚”,而是为了跨越语言、跨越平台、跨越时间。
这才是它真正有价值的地方。
版本:第一版
发布日期:2026年7月13日
作者:周方勇/咏方舟-长江支流(金质打印通、用宝框架开源作者)
适用范围:所有基于 UserBaoTech.Foundation 的新项目开发
反馈与交流:欢迎在评论区留言或私信交流。如果你正在寻找一套不用 EF、不用 Dapper、可跨语言迁移的轻量级基架,用宝框架或许是一个值得尝试的选择。
用宝框架,拥抱第一 · 一次书写 · 三端复用——不仅是用户的朋友,而且是用户的宝贝
