【问题标题】:Delayed Ninject setter method injection延迟的 Ninject setter 方法注入
【发布时间】: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


【解决方案1】:

有很多方法可以做到这一点。但总的来说,如果你有这样的循环依赖,那么你的设计就走错了路。几乎没有充分的理由产生循环依赖。它们使许多事情变得更加复杂,而不仅仅是构建您的实例。您很容易会得到一个难以维护的完全错综复杂的设计。

如果你真的想不顾我的警告走这条路,那就看看工厂扩展和对 Lazy 的支持。我不会给你更多提示,因为我真的认为这根本不是一个好的设计。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-23
    • 2019-11-17
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多