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

基于Prism6的WPF应用中Unity容器何时处置注入对象?

关于Prism 6 + Unity下依赖对象的处置时机梳理

我之前在做Prism 6 + Unity的WPF项目时,也纠结过UoW、DbContext这类对象的Dispose时机问题,结合实践给你拆解下关键逻辑:

1. 先明确Unity的生命周期配置

你在注册依赖时,有没有指定生命周期管理器?这直接决定了对象的存活时长:

  • TransientLifetimeManager:每次解析都创建新实例,容器不会持有引用,这类对象的Dispose需要你手动触发(比如在ViewModel的Dispose里调用)。
  • ContainerControlledLifetimeManager(单例):整个应用生命周期只有一个实例,只有当Unity容器被Dispose时,才会触发它的Dispose方法。
  • PerResolveLifetimeManager:每次解析请求创建一个实例,适合UoW这种和单次业务请求绑定的场景。

一般来说,DbContext和UoW不建议注册为单例——因为DbContext是有状态的,长期持有会导致缓存膨胀、并发问题,更合理的是和ViewModel同生命周期。

2. Prism ViewModel的Dispose触发时机

如果你的ViewModel实现了IDisposable接口,Prism会在View被销毁时自动调用它的Dispose方法:

  • 对于窗口类View:当窗口关闭(不是最小化)时,View会被销毁,ViewModel的Dispose会触发。
  • 对于导航页View:当你导航离开该页面,且没有设置KeepAlive="True"时,View会被销毁,ViewModel的Dispose也会触发。

这就是为什么你应该把UoW、DbContext的Dispose逻辑绑定到ViewModel的Dispose上——ViewModel的生命周期和用户交互的页面/窗口绑定,能确保资源在合适的时机被释放。

3. 正确的Dispose实现示例

ViewModel中的Dispose

public class OrderViewModel : BindableBase, IDisposable
{
    private readonly IOrderUnitOfWork _orderUow;
    private bool _disposed = false;

    public OrderViewModel(IOrderUnitOfWork orderUow)
    {
        _orderUow = orderUow;
    }

    // 这里写业务逻辑...

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // 手动触发UoW的Dispose,进而释放DbContext
                _orderUow.Dispose();
            }
            _disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

工作单元(UoW)的Dispose

public class OrderUnitOfWork : IOrderUnitOfWork, IDisposable
{
    private readonly AppDbContext _dbContext;
    private bool _disposed = false;

    public OrderUnitOfWork(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    // UoW的业务方法:比如SaveChanges()...

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // 释放DbContext
                _dbContext.Dispose();
            }
            _disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

4. 为什么你的断点没触发?

可能的几个原因:

  • 对象生命周期没到:比如ViewModel是单例,或者View设置了KeepAlive="True",导致View/ViewModel没被销毁,Dispose自然不会触发。
  • Unity容器没被Dispose:如果是单例对象,只有当Prism应用关闭时,PrismApplication才会自动Dispose Unity容器,这时候单例对象的Dispose才会执行。
  • 没手动触发Dispose:如果是Transient对象,容器不会帮你管理Dispose,必须在持有它的对象(比如ViewModel)的Dispose里手动调用。

5. 注册依赖时的建议

在Prism的RegisterTypes方法里,给UoW和DbContext配置合适的生命周期:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    // 用PerResolve或者Transient,确保每次ViewModel获取的都是新实例
    containerRegistry.Register<IOrderUnitOfWork, OrderUnitOfWork>(new PerResolveLifetimeManager());
    containerRegistry.Register<AppDbContext>(new PerResolveLifetimeManager());
}

这样每次解析ViewModel时,都会创建新的UoW和DbContext实例,当ViewModel被销毁时,通过它的Dispose就能链式释放这些资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:43:24