代码之家  ›  专栏  ›  技术社区  ›  InteXX

使用LifetimeScope会导致ObjectDisposedException

  •  0
  • InteXX  · 技术社区  · 1 年前

    我试图更好地理解IoC/DI,特别是作用域的概念。

    我正在使用一个示例WPF应用程序(repo here )来自 Pluralsight course (服务很好,BTW)并稍作修改。当然,在我改变之前,它运行良好。

    这是 original code :

    Private Sub App_Startup(Sender As App, e As StartupEventArgs) Handles Me.Startup
      Dim oBootStrapper As BootStrapper
      Dim oContainer As IContainer
      Dim oMainView As MainView
    
      oBootStrapper = New BootStrapper
      oContainer = oBootStrapper.GetContainer
      oMainView = oContainer.Resolve(Of MainView)
      oMainView.Show()
    End Sub
    

    …以下是我将其更改为:

    Private Sub App_Startup(Sender As App, e As StartupEventArgs) Handles Me.Startup
      Dim oBootStrapper As BootStrapper
      Dim oContainer As IContainer
      Dim oMainView As MainView
    
      oBootStrapper = New BootStrapper
      oContainer = oBootStrapper.GetContainer
    
      Using oScope As ILifetimeScope = oContainer.BeginLifetimeScope
        oMainView = oScope.Resolve(Of MainView)
        oMainView.Show()
      End Using
    End Sub
    

    然而,这会导致 ObjectDisposedException 当我尝试添加新朋友时:

    enter image description here

    无法解析实例,也无法从此LifetimeScope创建嵌套生存期,因为它(或其父作用域之一)已被释放。

    这一切似乎与我在 official documentation :

    始终从生存期范围而不是根容器解析服务是很重要的。

    这一指导意见使我首先介绍了范围。但是,如果一个作用域处理了应用程序运行所需的对象,我们怎么能希望使用它呢?此外,我们为什么要使用它?

    我很困惑。我建议的用法不正确吗?

    --编辑--

    为了澄清,我正在寻求官方指导提出的难题的解决方案:如果我们坚持我们的申请将失败。但如果我们不这样做,我们就有内存泄漏的风险(根据文档)。

    该怎么办?

    0 回复  |  直到 1 年前
        1
  •  2
  •   Travis Illig    1 年前

    官方指南可以帮助您防止无意中的内存泄漏。 由于Autofac保留了对一次性物品的引用,因此它可以进行处理,如果您直接从容器中解析1000个IDisposable项目,那么在不处理整个容器的情况下,就无法让垃圾收集来清理它们。

    如果你没有考虑到这一点,比如说,有一个长期运行的应用程序偶尔会处理数据库,这就特别糟糕了——这项工作可能会定期从容器中解析一次性数据库上下文,即使调用代码执行dispose,容器也会挂在它上面:内存泄漏。

    然而,把它和关于单身汉之类的文档放在一起。单身汉,即使你从子范围解决他们, 住在集装箱根部 为什么?因为如果你让一个作用域处理一个共享的单例,那么其他需要单例的东西都会有问题。

    “从范围内解决问题”指南旨在防止人们因内存泄漏而自食其果,因为他们没有意识到自己只是通过使用容器引入了内存泄漏。

    如果你正在解决的问题不是一次性的,并且该问题的整个依赖链中没有任何东西是一次性的,那么你 可能 安全地从集装箱中取出。

    这里更重要的教训是,要认真对待您的终身范围以及您希望如何处理处置。我不是一个WPF的人,但如果应用程序的主窗口需要解决,并且需要在应用程序的整个持续时间内运行,那么这似乎是单例应用程序的完美用途。。。它不会在该生存期结束时被处理,您也不会看到异常。Autofac也有一些方法可以让你选择不让它做处理,这会阻止它保存这些引用。

    但很难说“永远这样做”和“永远不要那样做”,因为正如你所看到的,生命周期范围和处置是一个复杂的话题。深入研究很重要 为什么? ,而内存管理和处理就是原因。出于同样的原因,正确使用已注册组件同样重要。