I am very new in Spring4D framework and ask the help.

I have next classes and interfaces:

ICommand = interface

TCommand = class(TInterfacedObject, ICommand)

IVecadCommand = interface(ICommand)

TVecadCommand = class(TCommand, IVecadCommand)

TVecadCommandJPG = class(TVecadCommand, IVecadCommand)

TCommandDeckelJPG = class(TVecadCommandJPG, IVecadCommand)

then I register a component:

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

then I try to create an object with the help of the ServiceLocator:

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

As a result of execution I have an exception:

Invalid class typecast

To avoid the exception I make so:

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

then everything is OK.

Point is I have to use it TContainer in this case as Repository for TCommand and inherited classes. So I must use ServiceLocator first way.

What should I do to avoid an exception and use ICommand but not IVecadCommand in TContainer?

Thanks. Will provide additional details with pleasure.

有帮助吗?

解决方案

You registered IVecadCommand but asked for ICommand.

The error is misleading and actually it should have raised an exception telling you that it doesn't know how to resolve that (seems like a bug - I will look into that).

That is because you can only ask for services that you registered explicitly. It does not look up the inheritance chain.

If you want to be able to resolve your class also as ICommand you need to add another .Implements<ICommand> to the registration. As names have to be unique and you probably want to resolve by name you have to give it a different name than the IVecadCommand. If you never want to resolve it as IVecadCommand (you can use supports once you resolved as ICommand) then just change the existing registration from IVecadCommand to ICommand.

Edit: I actually was not entirely correct - when you resolve by name the container does not check for the passed type. The problem in this case is converting IVecadCommand to ICommand which is done by TValue.AsType<T>. But it does not handle that correctly. I will fix that in an upcoming version. I just don't know how yet. For consistency it should be strict about the type here too. Anyway if you do what I stated above to solve the problem for now you are safe.

Update 10.04.2014: I have made a fix to this problem so now it should be possible to do a named resolve getting back a parent interface of the resolved one.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top