Search code examples
delphidependency-injectionspring4d

In Spring4D is it possible to register generic interfaces?


I have classes that have a constructor such as

constructor Create(Factory: IFactory<IConnection>)

When I try and register the IFactory in the container

Container.RegisterType<IFactory<IConnection>,TConnectionFactory> 

or

Container.RegisterType<TConnectionFactory>.Implements<IFactory<IConnection>>

I get an error stating that the interface does not have a guid.

I don't really want to add lots of pointless interfaces such as

IConnectionFactory = interface(IFactory<IConnection>)
  ['{45106BA8-43E7-4D26-B0EF-1639871B93E4}']
end;

to get around this but is this the only way?

Many thanks


Solution

  • As you found out the generic interface can have a GUID.

    That itself causes no harm until you QueryInterface/Supports IList<string> from something that is an IList<Integer> which would erroneously succeed and subsequently fail once you start working with it. FWIW since you mentioned those types while the collection interfaces all have guids there is no need to ever do such querying when using them but they are required internally which then stays within the same generic type argument.

    Currently the GUID is being used to check and get the interface from the implementing object because the RTL only supports doing that with a GUID and not with typeinfo.

    In fact following code would not raise an exception during the registration but eventually cause defects when being resolved:

    RegisterType<IFactory<IConnection>, TSomeFactory> where TSomeFactory implements IFactory<ISomethingElse>

    However there is some rather hidden typeinfo available (see the commented line in System.TInterfaceTable) that has the exact typeinfo of the implemented interfaces. Spring4D internally uses that at some places, for example Spring.Reflection.TRttiTypeHelper.GetInterfaces. That could be used but then there is another catch: generic types across multiple modules have different typeinfo. So it's not so easy to simply use that information to validate during registration and query the interface from the implementing class because right now the container (via some extension) supports registrations and dependencies across multiple modules.

    Making the registration more robust and if possible remove the requirement for having a GUID on the interface is something I have on my list for the container refactoring which is planned for later this year.