如果不能解析所有参数,Spring4D 不应调用继承的构造函数

Spring4D should not call inherited constructor if not all parameters can be resolved

我们使用 Spring4D 的依赖注入框架,如果它不能解析所有构造函数参数,那么它构造对象的方式就会有问题。在我们的例子中,祖先构造函数的所有参数都可以解析,看起来 Spring4D 现在使用这个构造函数。即使我们reintroduce后代的构造函数,它仍然使用祖先的构造函数。

但是,我期望(并且更喜欢)的行为是,如果无法为您尝试解析的接口找到正确的构造函数,解析将失败。

示例:

TMyClass = class(TInterfacedObject, IMyClass)
  constructor Create(ARequester: IRequester);
end;

TMyDescendant = class(TMyClass, IMyDescendant)
  constructor Create(ARequester: IRequester; AnotherRequester: IOtherRequester);
end;

GlobalContainer.Resolve<IMyDescendant>

在这个例子中,如果没有注册的 class 实现 IOtherRequester,它将调用 TMyClass 的构造函数。这意味着 TMyDescendant 的构造函数中的任何 Guard.IsNotNull 都不起作用,因为永远不会调用该构造函数。

有没有办法解决这个问题?当然,我们可以在 TMyDescendant 中重写 TMyClass 的构造函数,但我更喜欢一种更简洁的方法。

这个问题有多种解决方案。

  1. 单元 Spring.Container.ActivatorExtension 中有一个容器扩展。 您只需像这样注册它:

    GlobalContainer.AddExtension<TActivatorContainerExtension>;
    

    这会将整个容器的构造函数发现行为更改为仅考虑具有任何构造函数的最派生class的构造函数,从而避免返回如果缺少任何依赖项,则为 TObject.Create

    请记住,即使你可以在你的两个参数构造函数上写重载并且没有注册 IOtherRequester 它因此不会去 TMyClass 构造函数,它可以满足你注册了一些 IRequester。这是因为 RTTI 不包含任何关于重载的信息,即使它会意味着容器必须实现重载决议,这可能会变得非常复杂。

  2. [Inject] 注释你的构造函数(记得将单元 Spring.Container.Common 添加到 uses 中,否则它不会有任何效果 - 取决于你随后将看到的编译器版本W1074 警告)

    这将强制容器只考虑这个构造函数而忽略任何其他构造函数。实际上,您可以用它来注释两个构造函数——它总是会首先找到最派生的构造函数。如果您要从 TMyClass 继承其他 classes 而这些 TMyClass 不引入自己的构造函数,它将强制使用 TMyClass 中的那个。