【发布时间】:2016-09-21 10:22:05
【问题描述】:
我们正在将 Ninject 依赖注入用于机器自动化软件,但遇到了循环引用问题。我们有几个物理对象需要相互了解以避免碰撞。我们添加了一个 CollisionHandler 类来授权每个动作。例如:机械臂在通过前检查舱门是否打开。舱门会在关闭前检查机械臂是否已移开。
我仅使用机器人和碰撞处理程序对Ninject setter method injection pattern 进行了概念验证测试。效果很好,首先创建了 Robot,然后是 CollisionHandler,最后在 Robot 上调用了注入方法。 Robot、Hatch 和 CollisionHandler 都绑定为单例:
Bind<Robot>().ToSelf().InSingletonScope()
Bind<Hatch>().ToSelf().InSingletonScope()
Bind<CollisionHandler>().ToSelf().InSingletonScope()
public class Robot
{
private CollisionHandler _collisionHandler;
public Robot(ISomeService someService)
{
}
[Inject]
public void PostConstructInject(CollisionHandler collisionHandler)
{
if (_collisionHandler != null)
throw new InvalidOperationException("PostConstructInject called more than once");
_collisionHandler = collisionHandler;
}
}
public class CollisionHandler
{
private readonly Robot _robot;
private readonly Hatch _hatch;
public CollisionHandler(Robot robot, Hatch hatch)
{
_robot = robot;
_hatch = hatch;
}
public bool IsRobotAwayFromHatch() { }
public bool IsHatchOpen() { }
}
一切看起来都很好,所以我继续为其他实体实现该模式。那就是它停止工作的地方。将注入方法添加到舱口,Ninject 不再能够构造对象图:
public class Hatch
{
private CollisionHandler _collisionHandler;
public Hatch(ISomeOtherService someOtherService)
{
}
[Inject]
public void PostConstructInject(CollisionHandler collisionHandler)
{
if (_collisionHandler != null)
throw new InvalidOperationException("PostConstructInject called more than once");
_collisionHandler = collisionHandler;
}
}
问题是Ninject想在构造对象后直接调用inject方法:
Activation path:
4) Injection of dependency CollisionHandler into parameter collisionHandler of method PostConstructInjection of type Robot
3) Injection of dependency Robot into parameter robot of constructor of type CollisionHandler
2) Injection of dependency CollisionHandler into parameter collisionHandler of method PostConstructInjection of type Hatch
1) Request for Hatch
这等于以下代码:
Robot robot = new Robot(someService);
robot.PostConstructInject(/* We need a CollisionHandler instance before it is constructed */);
Hatch hatch = new Hatch(someOtherService);
CollisionHandler collisionHandler = new CollisionHandler(robot, hatch);
hatch.PostConstructInject(collisionHandler);
我想做的是在创建 CollisionHandler 实例之后将 PostConstructInject 调用移至:
Robot robot = new Robot(someService);
Hatch hatch = new Hatch(someOtherService);
CollisionHandler collisionHandler = new CollisionHandler(robot, hatch);
robot.PostConstructInject(collisionHandler);
hatch.PostConstructInject(collisionHandler);
有什么方法可以告诉 Ninject 在可能之前不要调用注入方法?我可以删除 [Inject] 属性并让 CollisionHandler 调用这些方法,但这感觉很丑。
【问题讨论】:
-
我认为您需要一种方法来编排整个过程,而不是让单个组件驱动系统。 Hatch 和 Arm 不应该互相关心,他们有特定的事情要做,由编排器(可能是机器人类)来处理。这很好,因为它使您的组件保持简单和健壮,并允许分离职责。
标签: c# dependency-injection ninject circular-reference