I am trying to develop a library using dependency injection approach (with Ninject) and I am having some kind of confusion likely because of my incorrect design. In summary, my design approach is
- A
parent
object has acommon
object. - A
parent
object uses some variable number ofchild
objects. - All
child
objects should use the very samecommon
object instance with theirparent
object
Here is a simple model of my problem domain.
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();
}
}
Problem 1
Number of needed child
objects vary. For example, according to return value of c1.DoSomething
I may or may not need other child objects. So I do not want to inject them through constructor and just create them when they are needed. But this approach causes violation of Hollywood Principle.
Question 1
How this violation can be prevented, without injecting child objects through constructor?
Problem 2
I want child
objects to use same common
object instance with their parent
object. So life time of common
object should be same as its parent.
If there is no life time is defined for ICommon then all
child
objects will have their owncommon
object instance.If life time of ICommon is defined in Thread or Request scope then I cannot use different instances of
parent
object in same Thread or Request scope. Because eachparent
object should use their own brand newcommon
object and dispose it.
So I could not solve it using life time scope options that I know. I produced another solution for this second problem but it makes code worse.
First, instead of injecting ICommon
into parent
object, parent
object it self creates it through ObjectFactory
class Parent : IParent {
private readonly ICommon _common;
public Parent() {
_common = ObjectFactory.GetInstance<ICommon>();
}
.....
Then, instead of injecting ICommon
into child
object, parent
object sets common
object of child objects.
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();
}
}
But this solution violates Hollywood Principle again and I have to set Common property of each child
object.
Question 2
How can parent
object distribute its common
object to child
objects using Dependency Injection? (preferably with Ninject)
Question 3
This is a little bit more general about my problem: How can Dependency Injection applied correctly to this model?
NOTE: ObjectFactory.GetInstance
calls Kernel.Get
of Ninject
You need to use either the CallScope
or the NamedScope
. These are part of the Ninject.Extensions.NamedScope
package. This allows you to scope the common object to the parent so all child requests receive the same common.
Regarding the child object creation. If you have to request child objects depending on some algorithm you need to instantiate it with a factory. Use the Ninject.Extensions.Factory
package to achieve this. This does a context preserving get and passes the parent context to the child request and therefore allows to reuse your common object also in the children which are created by the factory.
So in the end there will be no need to use your own object factory.
来源:https://stackoverflow.com/questions/14554151/dependency-injection-and-life-time-of-idisposable-objects