依赖项注入和 IDisposable 对象的生存期

本文关键字:对象 生存期 IDisposable 注入 依赖 | 更新日期: 2023-09-27 17:56:11

我正在尝试使用依赖注入方法(使用 Ninject)开发一个库,但由于我的设计不正确,我可能会感到困惑。总之,我的设计方法是

  1. parent对象具有common对象。
  2. parent对象使用一些可变数量的child对象。
  3. 所有child对象都应使用相同的common对象实例及其parent对象

这是我的问题域的简单模型。

interface IParent : IDisposable {
    void Operation();
}
interface ICommon : IDisposable {
    void DoCommonThing();
}
interface IChild1 {
    void DoSomething();
}
interface IChild2 {
    void DoAnotherThing();
}
class Parent : IParent {
    private readonly ICommon _common;
    public Parent(ICommon common) {
        _common = common;
    }
    public void Dispose() {
        _common.Dispose();
    }
    public void Operation() {
        var c1 = ObjectFactory.GetInstance<IChild1>();
        c1.DoSomething();
        var c2 = ObjectFactory.GetInstance<IChild2>();
        c2.DoAnotherThing();
        // number of childs vary, do things until cn
        _common.DoCommonThing();
    }
}
class Common : ICommon {
    private bool _isDisposed;
    public void Dispose() {
        _isDisposed = true;
    }
    public void DoCommonThing() {
        if (_isDisposed) 
            throw new Exception("Common Object is Disposed");
    }
}
class Child1 : IChild1
{
    private readonly ICommon _common;
    public Child1(ICommon common) {
        _common = common;
    }
    public void DoSomething() {
        // Do Something...
        _common.DoCommonThing();
    }
}
class Child2 : IChild2 {
    private readonly ICommon _common;
    public Child2(ICommon common) {
        _common = common;
    }
    public void DoAnotherThing() {
        // Do Another Thing...
        _common.DoCommonThing();
    }
}

问题1

所需的child对象数量各不相同。例如,根据返回值c1.DoSomething我可能需要也可能不需要其他子对象。所以我不想通过构造函数注入它们,只是在需要时创建它们。但这种做法违反了好莱坞原则。

问题1

如何在不通过构造函数注入子对象的情况下防止这种冲突?

问题2

我希望child对象与其parent对象使用相同的common对象实例。因此common对象的生命周期应与其父对象相同。

  1. 如果没有为 ICommon 定义生存期,则所有对象都将child都有自己的common对象实例。

  2. 如果 ICommon 的生命周期是在线程或请求作用域中定义的,那么我不能在同一线程或请求作用域中使用parent对象的不同实例。因为每个parent对象都应该使用自己的全新common对象并对其进行处置。

所以我无法使用我知道的终身范围选项来解决它。我为第二个问题提供了另一个解决方案,但它使代码变得更糟。

首先,不是将ICommon注入到对象parent而是parent对象通过ObjectFactory

class Parent : IParent {
    private readonly ICommon _common;
    public Parent() {
        _common = ObjectFactory.GetInstance<ICommon>();
    }
.....

然后,parent对象集common子对象的对象,而不是将ICommon注入到child对象中。

interface IChild {
    ICommon Common { get; set; }
}
interface IChildN : IChild {
     void DoNthThing();
}
abstract class ChildBase : IChild {
    ICommon IChild.Common { get; set; }
}
class ChildN : IChildN {
     public void DoNthThing() { }
}
class Parent : IParent {
    private readonly ICommon _common;
    public void Operation() {
        var c1 = ObjectFactory.GetInstance<IChild1>();
        c1.Common = _common;
        c1.DoSomething();
        var c2 = ObjectFactory.GetInstance<IChild2>();
        c2.Common = _common;
        c2.DoAnotherThing();
        _common.DoCommonThing();
    }
}

但是这个解决方案再次违反了好莱坞原则,我必须设置每个child对象的公共属性。

问题2

对象如何使用依赖注入将其common对象分发parent child对象?(最好使用宁注射)

问题3

关于我的问题,这有点笼统:依赖注入如何正确应用于此模型?

注意:ObjectFactory.GetInstance调用 Ninject 的Kernel.Get

依赖项注入和 IDisposable 对象的生存期

您需要

使用 CallScopeNamedScope 。这些是Ninject.Extensions.NamedScope包的一部分。这允许您将公共对象的作用域限定为父对象,以便所有子请求都接收相同的公共对象。

关于子对象的创建。如果必须根据某些算法请求子对象,则需要使用工厂对其进行实例化。使用 Ninject.Extensions.Factory 包来实现此目的。这会执行上下文保留 get 并将父上下文传递给子请求,因此允许在工厂创建的子对象中重用您的公共对象。

因此,最终将不需要使用自己的对象工厂。