.NET 默认依赖注入容器:Microsoft.Extensions.DependencyInjection 架构解析与自定义容器集成指南
.NET 默认依赖注入容器Microsoft.Extensions.DependencyInjection 架构解析与自定义容器集成指南【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime导读Microsoft.Extensions.DependencyInjection是 .NET 官方内置的默认依赖注入DI容器实现它与Microsoft.Extensions.DependencyInjection.Abstractions抽象层组合使用既可以直接承担应用的注册与解析工作也可以作为适配桥梁让 Autofac、DryIoc、Grace 等第三方容器接入统一的抽象接口。本文以当前 runtime 仓库中该库的真实源码src/libraries/Microsoft.Extensions.DependencyInjection为依据讲解默认容器的构建流程、服务解析引擎、验证机制与部署方式并给出使用其他容器替换或增强默认容器的完整路径帮助你理解 DI 容器的底层原理并在项目中正确选型。一、默认容器与 Abstractions 抽象层的关系正如仓库中 README.md 开篇所述Microsoft.Extensions.DependencyInjectionis combined with a core DI abstraction underMicrosoft.Extensions.DependencyInjection.Abstractionsthat allows for building different kinds of dependency injection containers to retrieve services from that have been registered with different lifetimes.这句话揭示了该库的核心设计理念具体容器实现Microsoft.Extensions.DependencyInjection与容器抽象Microsoft.Extensions.DependencyInjection.Abstractions是分离的。抽象层定义了IServiceProvider、IServiceCollection、IServiceScope、IServiceScopeFactory、ServiceDescriptor、IServiceProviderIsService、IKeyedServiceProvider等核心契约而具体容器实现则在抽象之上提供完整的服务注册与解析能力支持 Transient / Scoped / Singleton 三种生命周期从 .NET 8 起支持键控服务keyed services允许按serviceKey解析服务开箱即用的IServiceProvider实现ServiceProvider类与构建扩展方法BuildServiceProvider。这种抽象与实现分离的架构正是可以构建不同种类的 DI 容器来检索以不同生命周期注册的服务的根基任何符合抽象层契约的容器实现都可以在保持IServiceProvider使用方式不变的前提下无缝替换默认实现。二、注册、构建与解析默认容器的最小使用路径2.1 构建 ServiceProvider从IServiceCollection构建出可用的IServiceProvider核心入口是ServiceCollectionContainerBuilderExtensions中定义的一组扩展方法见 src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceCollectionContainerBuilderExtensions.cspublic static ServiceProvider BuildServiceProvider(this IServiceCollection services); public static ServiceProvider BuildServiceProvider(this IServiceCollection services, bool validateScopes); public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options);三个重载最终都汇聚到同一个构造函数调用new ServiceProvider(services, options)。其中无参版本使用静态共享的ServiceProviderOptions.Default实例避免在默认场景下额外分配对象源码中internal static readonly ServiceProviderOptions Default new ServiceProviderOptions();的注释即说明这一优化意图validateScopes重载等价于传入new ServiceProviderOptions { ValidateScopes validateScopes }。一个典型的最小示例using Microsoft.Extensions.DependencyInjection; ServiceCollection services new(); services.AddSingletonIIdGenerator, GuidIdGenerator(); services.AddScopedIUserRepository, UserRepository(); services.AddTransientINotifier, EmailNotifier(); using ServiceProvider provider services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes true, ValidateOnBuild true, }); IIdGenerator generator provider.GetRequiredServiceIIdGenerator();2.2 内置服务的自动注册在ServiceProvider的构造函数中src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs除了用户注册的描述符之外容器还会无条件注入四类内置服务内置服务类型实现用途IServiceProviderServiceProviderCallSite允许服务自身注入容器进而按需解析其他服务IServiceScopeFactoryConstantCallSite绑定根ServiceProviderEngineScope创建子作用域是Scoped生命周期的支撑IServiceProviderIsServiceCallSiteFactory查询某个类型是否已注册供框架与用户代码判断IServiceProviderIsKeyedServiceCallSiteFactory查询某个键控服务是否已注册CallSiteFactory同时实现了IServiceProviderIsService与IServiceProviderIsKeyedService源码注释明确要求这份内置服务清单必须与CallSiteFactory.IsService保持同步是理解容器哪些服务永远可用的关键。2.3 生命周期与缓存位置的映射三种生命周期的实现本质上对应CallSiteResultCacheLocation枚举中的缓存位置见 src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteResultCacheLocation.csSingletonRoot实例缓存在根作用域中整个容器只创建一次。ServiceProvider.CreateServiceAccessor对Cache.Location CallSiteResultCacheLocation.Root的调用点做了专门优化直接通过CallSiteRuntimeResolver.Instance.Resolve(callSite, Root)在首次访问时立即解析并固化结果之后的每次解析都直接返回已缓存实例ScopedScope实例缓存在每个ServiceProviderEngineScope的ResolvedServices字典中同一个作用域内共享跨作用域各自独立TransientDispose/None每次解析都新建实例若实例实现了IDisposable/IAsyncDisposable会被CaptureDisposable捕获到当前作用域的_disposables列表中随作用域一起释放。作用域对象ServiceProviderEngineScopesrc/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs同时实现IServiceScope、IServiceProvider、IKeyedServiceProvider、IServiceScopeFactory、IAsyncDisposable其释放逻辑Dispose/DisposeAsync会逆序遍历捕获的可释放服务并支持同步与异步两种释放路径对同时通过多个工厂注册解析出的同一共享实例还会在释放前做引用级去重保证只释放一次。三、解析引擎从解释执行到动态编译的渐进优化默认容器解析性能的核心秘密在于它的引擎设计。ServiceProvider的GetEngine()方法src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs根据运行环境选择引擎在 .NET Framework 与 .NET Standard 2.0 目标上或当前运行时支持动态代码编译RuntimeFeature.IsDynamicCodeCompiled且未通过 AppContext 开关禁用时使用DynamicServiceProviderEngine在 NativeAOT 等不支持动态代码编译的环境下退回到RuntimeServiceProviderEnginesrc/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/RuntimeServiceProviderEngine.cs采用纯解释方式逐次访问调用点图。DynamicServiceProviderEnginesrc/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/DynamicServiceProviderEngine.cs采用首次解释 后台编译替换的策略服务第一次被解析时直接走CallSiteRuntimeResolver的解释执行路径立即返回结果不阻塞调用方当同一调用点被解析到第 2 次时Interlocked.Increment(ref callCount) 2通过ThreadPool.UnsafeQueueUserWorkItem在后台线程用CompiledServiceProviderEngine编译出高效的解析委托随后用ReplaceServiceAccessor原子替换掉旧访问器后台编译使用UnsafeQueueUserWorkItem刻意不捕获 ExecutionContext避免不必要的上下文开销编译失败也会被捕获并记录到事件源不会影响已返回的正确结果。编译引擎本身又分为两种实现二者共同继承ServiceProviderEngine抽象方法RealizeService定义了解析委托的生产方式见 src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngine.csExpressionsServiceProviderEngineExpressionsServiceProviderEngine.cs基于System.Linq.Expressions构造表达式树后编译ILEmitServiceProviderEngineILEmitServiceProviderEngine.cs直接生成动态 IL 方法避免表达式树本身的解释开销。整个过程以CallSiteFactorysrc/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs为核心它把注册的ServiceDescriptor[]加工成结构化的ServiceCallSite调用点图缓存到ConcurrentDictionaryServiceCacheKey, ServiceCallSite中并负责检测构造器循环依赖、校验开放泛型注册例如开放泛型服务必须对应开放泛型实现、实现类型不能是抽象类或接口等规则均在Populate阶段完成。StackGuard则用于防止极端嵌套解析导致的栈溢出。四、配置选项ValidateScopes 与 ValidateOnBuild默认容器的行为可以通过 ServiceProviderOptions.cs 中的两个开关控制选项默认值作用ValidateScopesfalse开启作用域验证确保Scoped 服务永远不会从根提供程序root provider被解析。开启后ServiceProvider会创建CallSiteValidator在解析时通过OnCreate/OnResolve钩子校验调用点与作用域的关系ValidateOnBuildfalse在调用BuildServiceProvider构建容器时立即验证所有服务都能被成功构造。构建期间遍历全部ServiceDescriptor逐一尝试生成调用点任何失败都会汇总为AggregateException消息为 Some services are not able to be constructed抛出开放泛型服务open generic services不参与此项验证源码注释中明确说明两者的典型实践ServiceProvider provider services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes true, // 开发环境强烈建议开启可立即暴露Scoped 服务从根容器解析的隐患 ValidateOnBuild true, // 启动时即验证所有注册可构造把错误前移到进程启动阶段 });从源码层面看ValidateOnBuild的实现位于ServiceProvider构造函数内逐个调用ValidateService并捕获每个失败描述符的异常聚合成列表最终一次性抛出AggregateException而ValidateScopes对应CallSiteValidator的调用点校验逻辑属于运行时解析路径上的即时检查。五、部署方式OOB带外NuGet 包README.md 的 Deployment 一节明确了该库的部署形态Microsoft.Extensions.DependencyInjectionis not included in the shared framework. The package is deployed as out-of-band (OOB) and needs to be installed into projects directly.也就是说Microsoft.Extensions.DependencyInjection不属于共享框架shared framework的组成部分而是以带外out-of-band, OOBNuGet 包的形式独立发布使用时必须显式安装到项目中。与之形成对比的是很多基础库随共享框架提供、无需单独引用。这一特性对实际工程的影响包括使用默认容器时需在项目文件中显式添加包引用版本以 NuGet 上发布的实际版本为准OOB 的版本节奏独立于 .NET 运行时版本新特性例如 .NET 8 引入的键控服务可以更早地以包形式提供给旧版本运行时使用在 runtime 仓库中该库的源码位于 src/libraries/Microsoft.Extensions.DependencyInjection并带有独立的解决方案文件Microsoft.Extensions.DependencyInjection.slnx便于按包粒度独立构建与测试。六、使用其他容器替换或增强默认容器这是 README 中篇幅最大的主题也是该库抽象与实现分离设计的最直接受益场景。Microsoft.Extensions.DependencyInjection.Abstractions只定义契约因此任何实现了该契约的第三方容器都可以通过适配层接入让业务代码继续使用IServiceProvider、IServiceCollection等标准接口同时获得第三方容器的高级能力如属性注入、AOP 拦截、更细粒度的生命周期控制等。README 列出的主流集成容器包括Autofac、DryIoc、Grace、Lamar、LightInject、StructureMap、Stashbox、Unity等。在当前 runtime 仓库中这一兼容性承诺由 tests/DI.External.Tests 测试工程直接验证该目录下提供了针对 Autofac、DryIoc、Grace、Lamar、LightInject、StashBox 的适配测试文件Autofac.cs、DryIoc.cs、Grace.cs、Lamar.cs、LightInject.cs、StashBox.cs并包含一个可跳过的兼容性规范测试基类SkippableDependencyInjectionSpecificationTests——这套测试套件以统一的方式对每个第三方容器运行同一组 DI 规范断言从而保证注册的服务能以不同生命周期被正确检索这一核心行为在任何容器下都不打折扣。集成第三方容器的通用接入模式大致如下以实际容器文档为准// 1. 照常使用抽象层注册服务 IServiceCollection services new ServiceCollection(); services.AddScopedIMyService, MyService(); // 2. 通过容器提供的 Populate/适配扩展将 IServiceCollection 的描述符导入第三方容器 // 例如ContainerBuilder builder new(); // builder.Populate(services); // 3. 构建出实现 IServiceProvider 的第三方容器实例交给宿主 // IServiceProvider provider container.Build();选择要点保持宿主兼容ASP.NET Core 等宿主框架依赖IServiceProvider与IServiceScopeFactory只要第三方容器正确实现这些契约即可无缝替换权衡取舍默认容器在本次仓库源码中已内置解释执行 后台编译的渐进优化对绝大多数场景足够高效第三方容器则适合需要拦截、属性注入等扩展能力的团队可测试性可以参考仓库中的 DI.External.Tests 模式为自己的容器适配层建立规范化的兼容性测试。七、可观测性内置的 EventSource 诊断支持默认容器还内置了基于System.Diagnostics.Tracing.EventSource的诊断能力实现在 DependencyInjectionEventSource.cs 中EventSource 名称为Microsoft-Extensions-DependencyInjection采用自描述事件格式EtwSelfDescribingEventFormat以保持向后兼容提供ServiceProviderBuilt、ServiceProviderDisposed、ServiceResolved、CallSiteBuilt、ServiceRealizationFailed、ScopeDisposed等事件覆盖容器从构建、解析到释放的完整生命周期CallSiteBuilt事件会携带格式化后的调用点树与描述符信息由于事件源不支持超大载荷实现中会将大载荷按 10KB 分块MaxChunkSize发送容器内部维护WeakReferenceServiceProvider列表跟踪活跃提供程序并有针对性地清理失效引用避免事件源侧的泄漏。对生产环境而言可以通过dotnet-trace等工具订阅该事件源快速定位某个服务为何被频繁解析容器何时被构建/释放等性能与生命周期问题。八、贡献标准与成熟度定位README 的 Contribution Bar 一节说明该库的维护边界新特性new features、新 API、缺陷修复与性能优化均在欢迎之列对应的主要贡献门槛参见 src/libraries/README.md该链接在 README 中以../../libraries/README.md#primary-bar形式给出仓库根视角即为src/libraries/README.md。同时 README 也明确该库的 API 与功能已经成熟mature但偶尔仍会扩展——这解释了为什么它不常变动却又不断有键控服务、动态引擎优化等新能力落地。从仓库结构也能看到这一演进的痕迹ServiceProvider同时支持IServiceProvider与IKeyedServiceProvider测试工程中包含 KeyedServiceProviderContainerTests.cs 等针对新能力的专项测试。九、深入阅读指引若想继续深入建议按以下路径在仓库中追踪实现抽象层契约Microsoft.Extensions.DependencyInjection.Abstractions目录src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions定义了IServiceProvider之外的全部注册/解析接口容器入口 ServiceProvider.cs 与 ServiceCollectionContainerBuilderExtensions.cs调用点图与校验ServiceLookup 目录重点看CallSiteFactory.cs、CallSiteRuntimeResolver.cs、CallSiteValidator.cs与三种引擎实现生命周期与释放语义ServiceProviderEngineScope.cs行为验证测试tests/DI.Tests含循环依赖、作用域、键控服务、编译模式等 20 余个测试文件与 tests/DI.External.Tests第三方容器兼容性验证裁剪trimming适配tests/TrimmingTests 覆盖 AOT/裁剪场景下ActivatorUtilities与注册扩展的正确性。理解以上路径即可从会调用 API进阶到读懂容器每次解析背后的调用点构建、缓存决策与引擎切换逻辑进而在排障、性能调优和容器选型时做出更专业的判断。【免费下载链接】runtime.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.项目地址: https://gitcode.com/GitHub_Trending/runtime6/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Readest TTS 日语 ruby 注音朗读改造:基于节点过滤器实现「读假名、不读汉字」

Readest TTS 日语 ruby 注音朗读改造:基于节点过滤器实现「读假名、不读汉字」

桌面应用跨平台前端 【免费下载链接】readest Readest is a modern, feature-rich ebook reader designed for avid readers offering seamless cross-platform access, powerful tools, and an intuitive interface to elevate your reading experience. 项目地址:…

2026/9/21 14:43:02 阅读更多 →
Altium Designer交互式BOM插件安装与版本兼容指南

Altium Designer交互式BOM插件安装与版本兼容指南

做PCB这行久了,你会越来越觉得,BOM这东西做得好不好,直接决定贴片厂对你的态度。以前我导出的BOM要么是Excel、要么是PDF,一大串位号、封装、料号堆在一起,工人得对着板子上的丝印一个个找,找错了就焊错&am…

2026/9/21 14:43:02 阅读更多 →
OrCAD Capture报错警告本质解析与工程化应对策略

OrCAD Capture报错警告本质解析与工程化应对策略

1. 为什么“ERROR”和“Warning”不是报错,而是设计意图的翻译错误OrCAD Capture里弹出的红色ERROR和黄色Warning,绝大多数人第一反应是“软件出问题了”,立刻去搜“OrCAD报错怎么解决”,结果翻遍论坛、看十篇教程,发现…

2026/9/21 14:43:02 阅读更多 →

最新新闻

3天搞定博奥软件官网项目,源码解析避坑指南

3天搞定博奥软件官网项目,源码解析避坑指南

3天搞定博奥软件官网项目,源码解析避坑指南 看了一堆教程还是不会写项目?别慌,这很正常。很多开发者卡在“看会了”和“做出来”之间,就是因为缺一个完整的、能跑通的实战案例。…

2026/9/21 17:40:22 阅读更多 →
Java实现橱柜展示系统的3D渲染与优化实践

Java实现橱柜展示系统的3D渲染与优化实践

1. 项目背景与核心价值橱柜展示系统在现代家居设计和零售行业中扮演着越来越重要的角色。传统的纸质图册和静态展示已经无法满足消费者对个性化定制和沉浸式体验的需求。这个Java实现的橱柜展示系统,正是为了解决线下门店展示空间有限、设计方案沟通成本高等痛点而设…

2026/9/21 17:40:21 阅读更多 →
Spring Boot构建历史人物故事平台的技术实践

Spring Boot构建历史人物故事平台的技术实践

1. 项目背景与核心价值历史人物故事分享平台是一个典型的Web应用开发项目,采用Spring Boot框架作为技术基底。这类平台在文化传播领域具有特殊价值——它既满足了普通用户对历史知识的获取需求,又为历史爱好者提供了内容创作的出口。我在开发类似系统时发…

2026/9/21 17:40:21 阅读更多 →
超市仓库管理系统开发实战与优化指南

超市仓库管理系统开发实战与优化指南

1. 项目背景与核心价值超市仓库管理系统是零售行业数字化转型的基础设施,也是计算机专业学生常见的毕业设计选题。这个59803号项目源码提供了一个完整的仓库管理解决方案,涵盖了从商品入库到出库的全流程管理。我在实际零售系统开发中发现,这…

2026/9/21 17:40:21 阅读更多 →
Java关键字详解:核心作用与工程实践

Java关键字详解:核心作用与工程实践

1. 关键字在Java中的核心作用Java关键字是这门语言中最基础的构建模块,就像建筑工地上的钢筋水泥。这些被Java语言保留的特殊单词,每个都承载着特定的语法功能。作为从业15年的Java老司机,我见过太多开发者因为对关键字理解不透彻而写出"…

2026/9/21 17:40:21 阅读更多 →
2026最新ladyboy69版本升级API全变?3招搞定底层逻辑

2026最新ladyboy69版本升级API全变?3招搞定底层逻辑

2026最新ladyboy69版本升级API全变?3招搞定底层逻辑 昨晚还在跑通顺的脚本,今早一启动,满屏的 AttributeError 。那种感觉就像你熟练地掏出一把旧钥匙,却发现门锁已经被厂家偷偷换成了指纹锁。这就是 版本升级后…

2026/9/21 17:39:21 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →