如何在Spring4d中从ServiceLocator获取子接口实例?

时间:2014-03-31 13:12:22

标签: delphi spring4d

我是Spring4D框架中的新手并请求帮助。

我有下一个类和接口:

ICommand = interface

TCommand = class(TInterfacedObject, ICommand)

IVecadCommand = interface(ICommand)

TVecadCommand = class(TCommand, IVecadCommand)

TVecadCommandJPG = class(TVecadCommand, IVecadCommand)

TCommandDeckelJPG = class(TVecadCommandJPG, IVecadCommand)

然后我注册了一个组件:

GlobalContainer.RegisterComponent<TCommandDeckelJPG>.Implements<IVecadCommand>('deckel_jpg');

然后我尝试在ServiceLocator的帮助下创建一个对象:

var
  i: Integer;
  com: ICommand;
begin
  Result := nil;
  com := ServiceLocator.GetService<ICommand>(actionName);
  com.setSession(designSession);
  Result := com;
end;

作为执行的结果,我有一个例外:

Invalid class typecast

为了避免我这样做的例外:

var
  i: Integer;
  com: IVecadCommand;
begin
  Result := nil;
  com := ServiceLocator.GetService<IVecadCommand>(actionName);
  com.setSession(designSession);
  Result := com;
end;

然后一切都好。

要点是我必须在这种情况下使用TContainer作为TCommand的Repository和继承的类。所以我必须先使用ServiceLocator。

如何避免异常并在TContainer中使用ICommand而不是IVecadCommand?

感谢。将愉快地提供额外的细节。

1 个答案:

答案 0 :(得分:6)

您已注册IVecadCommand,但要求ICommand

该错误具有误导性,实际上它应该引发一个异常,告诉您它不知道如何解决(似乎是一个错误 - 我会调查)。

这是因为您只能要求您明确注册的服务。它没有查找继承链。

如果您希望能够以ICommand的身份解决您的课程,则需要在注册时添加另一个.Implements<ICommand>。由于名称必须是唯一的,并且您可能希望按名称解析,因此必须为其指定与IVecadCommand不同的名称。如果您永远不想将其解析为IVecadCommand(您可以在解析为ICommand后使用支持),则只需将现有注册从IVecadCommand更改为ICommand

编辑: 我实际上并不完全正确 - 当您按名称解析时,容器不会检查传递的类型。在这种情况下的问题是将IVecadCommand转换为ICommand,由TValue.AsType<T>完成。但它没有正确处理。我将在即将发布的版本中解决这个问题。我还不知道怎么回事。为了保持一致性,这里的类型也应该严格。无论如何,如果你做了我上面所说的解决问题,你现在就安全了。

更新10.04.2014: 我已经解决了这个问题所以现在应该可以做一个命名解决方案来获取已解决的一个的父接口。