Reputation: 3065
How can I dynamically construct a generic type in Delphi?
Let me explain
If I have an interface IMyInterface<T>
,
I want to dynamically assign the generic T
parameter and get a reference to that type somehow.
function GetInterfaced(aType : PTypeInfo) : TRttiType
begin
Result := ???
// I want to return TypeInfo(IMyInterface<aType>);
// or a RttiType that corresponds to TRttiContext.GetType(IMyInterface<aType>)
end;
How can I build this generic type dynamically ?
One restriction, I must not use
function GetInterfaced<T> : TRttiType
begin
Result := TrttiContext.Create.GetType(TypeInfo(IMyInterface<T>))
end;
edit
I am trying to create a type to resolve a component with Stefan's Spring4d container
For example :
function ResolveLookup(aModelType : PTypeInfo) : TObject
var aLookupType : PTypeInfo
begin
aLookupType := SomehowGetTypeOf(ILookup<aModelType>);
Result := FContainer.Resolve(aLookupType).AsObject;
end;
My real use case here is that I have defined a set of models (
TAssociate = class(TModel)
TUser = class(TModel)
TMandate = class(TModel)
I also defined "Lookup" views for them :
TAssociateLookup = class(TForm, ILookupView<TAssociate>);
I registered them in the container as
FContainer.RegisterType<TAssociateLookup, ILookupView<TAssociate>>);
I then defined a service
function TLookupService.GetLookupFor(aModelTypeInfo : PTypeInfo) : IInterface
begin
Result := FContainer.Resolve(SomeHowGetTypeOf(ILookupView<aModelTypeInfo>).AsInterface;
end
The problem is that i cannot use TLookupService.GetLookupFor<T>
, but I must use TLookupService.GetLookupFor(aTypeInfo : TTypeInfo)
This is due to the fact that interfaces cannot have generic members.
If I define a service interface like so I get a compilation error
ILookupService = interface
GetLookupFor<T> : ILookupView<T>; // compilation error
end;
So I must move the generic parameter here
ILookupService<T> = interface
GetLookup : ILookupView<T>;
end;
But this means that I must have an instance of the ILookupService for each type of lookup i want to use :
MyForm = class(TForm)
fAssociateLookupService : ILookupService<TAssociate>;
fMandateLookupService : ILookupService<TMandate>;
fTaskLookupService : ILookupService<TTask>
end;
instead of
MyForm = class(TForm)
fLookupService: ILookupService;
end;
This is why I wanted to define an interface like so
ILookupService = interface
GetLookupFor(aType : PTypeInfo) : IInterface;
end;
So I could use
procedure TMyForm.DoIt
var
aLookup : ILookupView<TMandate>;
begin
aLookup := fLookupService.GetLookupFor(TypeInfo(TMandate)) as ILookupView<TMandate>;
end;
Upvotes: 4
Views: 1128
Reputation: 400
I don't think the T can be dynamic, The compiler needs to know what type T will be at compile time.
The compiler creates a generic class for each type of T used. For example:
IMyInterface<TObjectType1>
IMyInterface<TObjectType2>
It doesn't create these at run time, they are created at compile time.
Upvotes: 9