Ludovic C
Ludovic C

Reputation: 3065

Delphi : How to create a generic type programatically?

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

Answers (1)

RoutineOp
RoutineOp

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

Related Questions