 —— 用宝轻量框架设计必读)
【开源】跨语言·跨平台·跨数据库 (2)—— 用宝轻量框架设计必读从“数组返回太土”说起六个设计原则看懂真正的跨语言架构咏方舟-长江支流 2026-07-13用宝框架拥抱第一 · 一次书写 · 三端复用C# / Java / ArkTS 直接使用不用重写——跨平台、跨语言全球第一套轻量级架构范式为什么敢说“拥抱第一”用宝框架是全球第一套同时做到以下三点的轻量级架构一解跨平台基于 .NET Standard 2.0Windows / 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]publicasyncTaskMessageResultProductGetList([FromQuery]ProductQueryquery){varrequestnewGetProductListRequest{Queryquery};returnawait_getListService.ExecuteAsync(request);}}}然后单步跟进去用宝框架的代码看到上面代码中的 MessageResult 当它返回分页数据时Rows 字段的类型就是 T[]在这里是 Product[]。他说怎么不用 List 你这也太土了吧“你这也太土了吧返回数据居然用T[]数组现在谁不用ListT啊”他没说错在 C# 里ListT确实更常用、更“现代”。但用宝框架选择T[]不是因为写代码的人水平不行而是因为——用宝框架的代码是要直接复制到 Java 和鸿蒙 ArkTS 里用的。T[]在 C#、Java、ArkTS 中都是原生语法不需要额外引入任何命名空间或类库。如果用了ListTJava 那边得换成ArrayListTArkTS 那边得换成ArrayT代码就“变形”了。所以不是用宝框架太土是提问的人没看懂它要跨什么。这就是用宝框架的第一个设计原则跨语言一致性。原则一跨语言一致性用宝框架的定位不是“又一个 C# 框架”而是一套可以在 C#、Java、ArkTS 之间直接复制的架构范式。具体做法接口命名统一IEntityTKey、IRepositoryT、IServiceTParam, TResult基类命名统一RepositoryBaseT、ServiceBaseTParam, TResult、KeyServiceBaseTResult返回结构统一MessageResultT数据类型统一T[]而不是ListTDictionarystring, 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:IEntitystring{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;}}好处数据库表加了新字段不影响查询参数查询参数加了新条件不影响实体前端只传它需要的字段不关心数据库内部结构原则六返回模型与实体分离用宝框架不直接把实体返回给前端而是通过MessageResultT和 DTO 进行隔离。为什么数据库里有密码字段返回时屏蔽掉数据库里有内部状态码如0、1、2返回时翻译成前端能看懂的中文数据库表有 20 个字段前端只关心 3 个只返回那 3 个// 实体存了密码publicclassUser:IEntitystring{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 的泛型设计publicclassMessageResultT:MessageResult{publicTData{get;set;}// 非分页数据publicintTotal{get;set;}// 分页总记录数publicT[]Rows{get;set;}// 分页数据列表}设计要点分页与非分页不混用分页只填RowsTotal非分页只填Data泛型让返回类型灵活MessageResultProduct返回产品MessageResultstring返回新增 ID前端只认五个字段success、message、data、rows、total所有接口都一样为什么不用ListT前面已经说过了——为了跨语言一致性。亮点二IEntity 的泛型设计publicinterfaceIEntityTKey{TKeyId{get;set;}DateTimeCreatedAt{get;set;}DateTimeUpdatedAt{get;set;}boolIsDeleted{get;set;}}为什么用泛型大部分表用stringGUID但旧系统可能需要int自增ID泛型让主键类型灵活不绑死任何一种CreatedAt、UpdatedAt、IsDeleted是所有实体都有的公共字段抽到接口里不重复定义亮点三KeyRequest 消灭重复 DTOpublicclassKeyRequest{publicstringId{get;set;}}问题每个实体都有按主键查询和按主键删除的需求如果每个都定义一个 DTOpublicclassGetProductByIdRequest{publicstringId{get;set;}}publicclassDeleteProductByIdRequest{publicstringId{get;set;}}publicclassGetUserByIdRequest{publicstringId{get;set;}}// ... 无穷无尽用宝框架的解决方案直接用KeyRequest配合KeyServiceBasepublicclassGetProductByIdKeyService:KeyServiceBaseMessageResultProduct{protectedoverrideasyncTaskMessageResultProductDoExecuteAsync(stringid){// 业务逻辑}}效果不需要为每个实体定义“按主键查询”和“按主键删除”的 DTO一个KeyRequest通吃。亮点四数据库提供者方言适配用宝框架的DataAccessExecutor内部通过DatabaseType枚举统一处理不同数据库的差异参数前缀SQL Server/MySQL 用Oracle 用:ODBC 用?分页 SQLSQL Server 用OFFSET FETCHMySQL 用LIMITOracle 用ROWNUM自增 ID 回读SQL Server 用SCOPE_IDENTITY()MySQL 用LAST_INSERT_ID()日期格式化Oracle 需TO_DATE其他数据库直接用字符串当前采用 switch 集中处理主流数据库方言后续准备改为提供者Provider模式支持用户自定义扩展同时保留默认实现确保开箱即用。效果业务层写的是标准 SQL完全感知不到数据库差异切换数据库时只改连接字符串业务代码一行不改新增数据库支持时只需在DataAccessExecutor中增加分支这个设计不是“写死”是“集中处理”。所有方言逻辑在一个地方上层干干净净。亮点五依赖注入传连接不自己建连接// Program.csvarconnectionStringbuilder.Configuration.GetConnectionString(Default);builder.Services.AddScopedIDbConnection(spnewMySqlConnection(connectionString));builder.Services.AddScopedIDataAccessExecutor(sp{varconnsp.GetRequiredServiceIDbConnection();varloggersp.GetRequiredServiceILogger();returnnewDataAccessExecutor(conn,DatabaseType.MySql,logger);});为什么这样设计用宝框架不负责连接的生命周期连接由上层应用管理上层可能已经建好了连接或者需要复用已有连接用宝框架只要求传入一个IDbConnection不关心它怎么来的这样框架能适配任何已经存在的系统而不是要求别人按你的方式建连接这是“依赖注入”的正解——框架不替你做决定只负责执行。结语用宝框架不是一个“炫技”的框架。它没有用最新的 .NET 语法没有用最酷的设计模式没有引入任何时髦的第三方库。它做的唯一一件事就是把 20 年经验中沉淀下来的、最稳定的设计原则固化成了一套可复用的代码结构。它的设计原则可以总结为跨语言一致性C# 写的代码可以直接在 Java 和 ArkTS 里用轻量化零依赖永不淘汰开放式设计所有组件可插拔、可替换单一职责每个类只做一件事实体与查询分离前端参数与数据库表互不干扰返回模型与实体分离不暴露内部存储细节所以下次有人看到用宝框架返回T[]说“太土了”你可以告诉他“不是太土了是你看不懂它的设计意图。”用宝框架的设计不是为了迎合某一种语言的“时尚”而是为了跨越语言、跨越平台、跨越时间。这才是它真正有价值的地方。版本第一版发布日期2026年7月13日作者周方勇/咏方舟-长江支流金质打印通、用宝框架开源作者适用范围所有基于 UserBaoTech.Foundation 的新项目开发反馈与交流欢迎在评论区留言或私信交流。如果你正在寻找一套不用 EF、不用 Dapper、可跨语言迁移的轻量级基架用宝框架或许是一个值得尝试的选择。用宝框架拥抱第一 · 一次书写 · 三端复用——不仅是用户的朋友而且是用户的宝贝