【问题标题】:Disposing components injected via constructor without lifetime scopes in Autofac在 Autofac 中处理通过构造函数注入的没有生命周期范围的组件
【发布时间】:2020-07-10 13:51:25
【问题描述】:

我不明白为什么我的组件永远不会在 Autofac 中处理/发布。 我有一个标准的 WPF 应用程序,它从 app.xaml.cs 开始,解析作为单例的 MainVM,并显示 MainWindowDataContextMainVM

然后我主要使用我的注册组件的构造函数注入,这些组件是单例或(默认)instancePerDependency,每次注入时都会创建新的。或者我有时有工厂来传递一些自定义参数。

例如,工厂如下所示:

public delegate MyComponent Factory(string parameter1, int parameter2);

注入看起来像这样:

public MainVM(MyComponent.Factory createMyComponent)
...
public void makeNewComponent()
{
  var myComponent = this.createMyComponent("test", 1);
  myComponent.DoStuff();
}

这就是我的组件的注册方式:

containerBuilder.RegisterType<T>().OnActivated(args => (args.Instance as IInitializable)?.Initialize());

builder.RegisterType<MyComponent>().As<IMyComponent>().OnActivated(args => (args.Instance as IInitializable)?.Initialize());

// This will never be called in my code: .OnRelease(instance => (instance as IInitializable)?.Uninitialize())*/;

现在让我们想象一下,我在其他视图模型中创建了许多这样的视图模型,所以我们有 MainVM -> MyComponent -> OtherComponent,并且在操作完成后我希望它们处理(或只是为了以某种方式从记忆中消失),调用Dispose()或从Autofac调用OnRelease事件。这些都可以。

但我的问题是 - 我没有使用这种模式:

using(var scope = container.BeginLifetimeScope())

'因为我没有在从 { 到 } 的一种方法中工作。我需要我的组件以多种方法存在于对象中,例如,在我从视图堆栈中删除ViewModel1 之后,我希望在此ViewModel1 中创建的所有内容都可以释放/释放其子项。是什么导致组件认为它们可以被丢弃?如果视图模型不是在生命周期范围内创建的,我如何告诉它不再需要它?

【问题讨论】:

    标签: c# .net wpf dependency-injection autofac


    【解决方案1】:

    您不应该关心没有实现IDisposable 的类。即使它们的实例是由 Autofac 容器创建的,一旦没有对它们的 GC 根引用(例如,视图已关闭并且对它的所有引用都是 null-ed),这些对象也会被自动 GC。这会影响整个依赖关系图——不管它有多深。

    如果您确实在您的设置中有IDisposable 对象,那么容​​器当然会保存对它们的引用,因为它需要处理这些对象。但是,您仍然可以控制这种情况的发生方式。

    您可以为此使用 IDisposable 依赖项的 Owned&lt;T&gt; 实例。

    考虑你的例子:

    class MainVM 
    {
        private readonly Owned<IMyComponent> _myComponent;
    
        public MainVM(Owned<IMyComponent> myComponent) => _myComponent = myComponent;
    
        public void DoStuff() => _myComponent.Value.DoStuff();
    
        public void OnViewClosed() => _myComponent.Dispose();
    }
    
    class MyComponent : IMyComponent, IDisposable
    {
        public MyComponent(IOtherComponent otherComponent) { /* ... */ }
    }
    
    class OtherComponent : IOtherComponent, IDisposable
    {
    }
    
    

    现在,当调用 OnViewClosed 方法时,MyComponent 的拥有实例将被处理掉,包括所有 MyComponent 的非共享、一次性依赖项 - 也就是说OtherComponent 在我们的示例中。

    考虑阅读文档中的owned instances

    【讨论】:

    • 不幸的是,我仍然不明白为什么 OnRelease 事件永远不会被调用。这里还有一个示例://function startsvar vm = createMyVM();var wnd = viewFactory.ResolveWindow(vm);if (wnd.ShowDialog() == true){//do stuff}//function ends 据我了解,离开此函数范围后,我的 VM 和 Window 不再需要。但是虚拟机永远不会被释放/释放:(
    • 据我所知 Autofac 的代码 - 在解析组件时有一行:e.Context.Resolve&lt;ILifetimeScope&gt;().Disposer.AddInstanceForDisposal((IDisposable) releaseAction1); 这是否意味着他需要一个生命周期来跟踪,否则他会得到全局的永远不会被处置?
    • OnRelease 只会为生命周期范围的对象调用。您不使用范围,因此您不会调用该方法。拥有的对象不需要生命周期范围。您可以通过Owned&lt;T&gt;.Dispose()手动控制范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多