延迟Ninject setter方法注入

时间:2016-09-21 10:22:06

标签: c# dependency-injection ninject circular-reference

我们正在为机器自动化软件使用Ninject依赖注入,并且遇到了循环引用的问题。我们有几个物理对象需要彼此了解以避免冲突。我们添加了一个CollisionHandler类,用于授权每个动作。例如:机器人手臂在移动之前检查舱口是否打开。舱口盖在关闭前检查机器人手臂是否挡开。

我只使用机器人和碰撞处理程序对Ninject setter method injection pattern进行了概念验证测试。这很好,首先创建了Robot,然后是CollisionHandler,最后在Robot上调用了inject方法。 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调用这些方法,但感觉非常难看。

1 个答案:

答案 0 :(得分:1)

有办法做到这一点。但总的来说,如果你有这样的循环依赖,那么你的设计就错了。几乎没有充分理由拥有循环依赖。他们使许多事情变得更加复杂,而不仅仅是构建你的实例。你很容易就会陷入一种难以维护的完全纠结的设计。

如果你真的想要遵循这条道路,尽管我有警告,而不是看看工厂扩展和对Lazy的支持。我不会给你更多提示,因为我认为这根本不是一个好的设计。