IDisposable对象的依赖注入和生命周期

时间:2013-01-28 01:10:34

标签: c# dependency-injection ninject idisposable object-lifetime

我正在尝试使用依赖注入方法(使用Ninject)开发一个库,并且由于我的设计不正确,我可能会遇到某种混淆。总之,我的设计方法是

  1. parent对象有一个common对象。
  2. parent对象使用一些可变数量的child个对象。
  3. 所有child个对象应使用与common对象相同的parent对象实例
  4. 以下是我的问题域的简单模型。

    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个对象使用与common对象相同的parent对象实例。因此common对象的生命周期应与其父对象相同。

    1. 如果没有为ICommon定义生命时间,则所有child个对象都将拥有自己的common对象实例。

    2. 如果在Thread或Request范围内定义了ICommon的生命周期,那么我就不能在同一个Thread或Request范围内使用parent对象的不同实例。因为每个parent对象都应使用自己的全新common对象并进行处理。

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

      首先,不是将ICommon注入parent对象,parent对象,而是通过ObjectFactory自我创建

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

      然后,ICommon对象不会将child注入parent对象,而是设置子对象的common对象。

      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对象的Common属性。

      问题2

      parent对象如何使用依赖注入将其common对象分发给child个对象? (最好是与Ninject一起)

      问题3

      关于我的问题,这是一个更普遍的问题:依赖注入如何正确应用于此模型?

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

1 个答案:

答案 0 :(得分:3)

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

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

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