You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行中C#应用能否通过DI容器更新服务实现并递归重建依赖?

在运行中C#应用通过DI部署新代码的可行性与实现方案

一、理论可行性

你的设想理论上是可行的,但需要解决几个核心技术问题:

  • 运行时代码加载:必须将新的Service实现编译为独立程序集(如.dll文件),通过Assembly.LoadFrom或Assembly.LoadFile在运行时动态加载。原有项目内的静态类无法直接替换,必须依赖外部编译的独立程序集。
  • DI容器的动态更新:.NET内置DI容器(IServiceCollection/ServiceProvider)是不可变的——一旦构建ServiceProvider,就无法修改已注册的服务。要实现递归更新依赖,要么使用支持动态注册/替换的第三方DI容器,要么自行封装容器管理逻辑。
  • 状态保留:要保留服务原有属性,需手动迁移状态——比如先获取旧服务实例,将需要保留的属性值复制到新实例中。这要求服务设计时预先考虑状态可迁移,或提供统一的状态导出/导入接口。

你设想的IServiceCollection.UpdateRecursively<IService, Service>()方法,核心逻辑应该是:

  1. 从DI容器中移除原IService的注册
  2. 注册新的Service实现
  3. 递归查找所有依赖IService的已注册服务,销毁旧实例并重新创建新实例(同时迁移状态)
  4. 对新创建的服务,继续递归处理其依赖链

二、现成实现

目前有成熟方案可实现类似需求:

  • 第三方DI容器:Autofac支持动态注册和组件替换,可通过ContainerBuilder重新构建容器并更新,结合生命周期管理实现依赖的递归重建;StructureMap也具备类似动态更新能力。
  • 插件框架:MEF(Managed Extensibility Framework)专为动态加载插件设计,支持运行时添加/替换导出服务,自动处理依赖关系。
  • 自定义封装:基于.NET内置DI,自行封装DynamicServiceProvider,维护可变更的服务注册集合,在更新时重新构建服务实例链并处理状态迁移。

三、在启动类外部访问DI容器

通常有两种合规方式:

  1. 全局静态引用:启动时将构建好的ServiceProvider保存到静态类的属性中,示例代码:
    public static class ServiceLocator
    {
        public static IServiceProvider Instance { get; set; }
    }
    
    // 在Program.cs中
    var provider = services.BuildServiceProvider();
    ServiceLocator.Instance = provider;
    
    注意:这种方式会增加代码耦合,需谨慎使用。
  2. 依赖注入传递:在需要访问容器的类中,直接注入IServiceProvider(或IServiceScopeFactory用于创建作用域),示例代码:
    public class SomeService
    {
        private readonly IServiceProvider _serviceProvider;
    
        public SomeService(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public void DoSomething()
        {
            var otherService = _serviceProvider.GetRequiredService<IOtherService>();
            // 业务逻辑
        }
    }
    
    这是符合DI设计原则的推荐方式。

内容的提问来源于stack exchange,提问作者LGhoul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:05:10