【问题标题】:Is there a disposing TransientLifetimeManager是否有处置 TransientLifetimeManager
【发布时间】:2011-08-19 06:58:49
【问题描述】:

我有一个具有相应 ViewModel 的 WPF 视图。所有实例都通过一个统一容器解决。因为我使用的是 prism,所以我需要两个独立的视图实例将其添加到视图注册到的两个不同区域中。如果我尝试将一个实例添加到两个区域中,我会得到一个

InvalidOperationException:指定 元素已经是逻辑子元素 的另一个元素。断开它 首先。

当视图被添加到第二个区域时,因为它已经添加到了第一个区域。

使用 TransientLifetimeManager 可以轻松解决此问题,该管理器始终返回一个新实例,因此两个区域都将填充一个独立的实例。

但是我们决定在新用户登录时创建一个子容器。每个与会话相关的视图和视图模型都使用此子容器解析。当用户的会话结束时,子容器被释放,因此每个与会话相关的实例也被释放。但是使用 TransientLifetimeManager 统一容器无法处理这些实例。

我们需要的是一个生命周期管理器,它总是返回一个新实例,但也能够处理这些实例。身边已经有这样的终身经理了吗?还是有其他方法可以实现我上面描述的?

【问题讨论】:

  • 对于那些阅读答案的人:“使有资格成为 GC'ed”并不“意味着调用 Dispose [立即,或从技术上]”。对于严格的范围/生命周期,这是一个很大的差异。

标签: mvvm unity-container prism


【解决方案1】:

您想要的听起来像是 ContainerControlledLifetime 管理器的变体,它不维护单例实例,而是一组实例。不幸的是,这不是内置的生命周期管理器之一。

您可以查看code for the ContainerControlledLifetimeManager 并发现它非常简单。您的“SynchronizedGetValue”实现将始终返回 null(向容器发出需要实例化新实例的信号)。您可以只继承 ContainerControlledLifetimeManager 并覆盖该方法。

我写的差不多了。我想我可以给你代码。 :)

public class ContainerTrackedTransientLifetimeManager :     
             ContainerControlledLifetimeManager
{
    protected override object SynchronizedGetValue()
    {
        return null;
    }
}

应该可以。我还没有测试过...从界面上看,它看起来像是为 1 对 1 LifetimeManager 与 Object 关系而设计的,但如果事实证明不止如此,您可能必须覆盖 SetValue(添加到集合对象)和处置(处置该对象集合)。这是那个实现:

public class ContainerTrackedTransientLifetimeManager : 
             SynchronizedLifetimeManager, IDisposable
{
    private ConcurrentCollection<object> values = new ConcurrentCollection<object>();

    protected override object SynchronizedGetValue()
    {
        return null;
    }

    protected override void SynchronizedSetValue(object newValue)
    {
        values.Add(newValue);
    }

    public override void RemoveValue()
    {
        Dispose();
    }

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

    protected void Dispose(bool disposing)
    {

         var disposables = values.OfType<IDisposable>();
         foreach(var disposable in disposables)
         {
              disposable.Dispose();
         }
         values.Clear();
    }

我不确定其中哪个是正确答案。让我知道你的情况。

【讨论】:

  • 是的,我昨天也试过了。我的第一种方法以及您的两种方法都可以在每次解析时创建一个新实例,但是当容器关闭时,所有三种方法都不会在已解析的对象上调用 Dispose。我错过了什么?
  • 该死的。我只是错过了类定义上的 IDisposable 接口。存在实现,但无法将对象强制转换为 IDisposable。尽管如此,我最终还是从 HierarchicalLifetimeManager 派生了 ContainerTrackedTransientLifetimeManager,以便在处置子容器时处置实例。
  • 我觉得这个想法是对的,但是如果不给Unity本身打补丁就做不到。如果我从 HierarchicalLifetimeManager 派生,则不会调用我的 SynchronizedGetValue 方法。如果我从 ContainerControllerLifetimeManager 派生,则在处置子容器时不会处置实例。因此我需要一个自定义的 BuilderStartegy。但这需要访问 LifetimeManager 的内部字段 IsUsed。所以我担心这不能从大会外部实现。
  • @PVitt:我今天有一些时间,所以我可以自己看看它并实际 尝试 :) 同时你可能只需要跟踪对象自己并使用 ExternallyControlledLifetimeManager。也许跟踪可以从您插入子容器中的对象完成,因此您只需处理一个点并且它的范围是正确的。
  • @PVitt:我还想提一下 Damian Schenkelman 关于循环引用的评论确实是正确的。只要将对象图与以 AppDomain 为根的图分开,就可以收集对象图,即使存在循环引用也是如此。 .NET 在技术上并不使用 refcount 来确定 GC 时间。我没有提到它,因为这不是你问的,但你可能会在错误的假设下走这条路。
【解决方案2】:

当您使用瞬态生命周期管理器(这是默认设置)时,Unity 不会保留对已创建实例的引用。

因此,当不再引用该实例时,它将被 GC。

【讨论】:

  • 就我们使用棱镜和“视图模型优先方法”而言,我们仍然有参考。视图和视图模型之间存在循环引用,它使用视图模型将自身设置为视图的数据上下文。
  • 如果循环引用是岛的一部分,也应该进行 GC。确保没有其他方法可以到达循环引用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-10
  • 2019-05-20
  • 1970-01-01
  • 2022-01-08
  • 2014-10-03
  • 2016-08-20
相关资源
最近更新 更多