Delphi:如何以编程方式创建泛型类型?

时间:2016-04-20 15:50:30

标签: delphi generics dynamic rtti

如何在Delphi中动态构建泛型类型?

让我解释一下

如果我有一个界面IMyInterface<T>

我想动态分配通用T参数,并以某种方式获取对该类型的引用。

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;

如何动态构建此通用类型?

一个限制,我不得使用

function GetInterfaced<T> : TRttiType
begin
    Result := TrttiContext.Create.GetType(TypeInfo(IMyInterface<T>))
end;

编辑

我正在尝试使用Stefan的Spring4d容器创建一个解析组件的类型

例如:

function ResolveLookup(aModelType : PTypeInfo) : TObject
var aLookupType : PTypeInfo
begin
    aLookupType := SomehowGetTypeOf(ILookup<aModelType>);
    Result := FContainer.Resolve(aLookupType).AsObject;     
end;

我的真实用例是我定义了一组模型(

TAssociate = class(TModel)
TUser = class(TModel)
TMandate = class(TModel)

我还为他们定义了“查找”视图:

TAssociateLookup = class(TForm, ILookupView<TAssociate>);

我在容器中将它们注册为

FContainer.RegisterType<TAssociateLookup, ILookupView<TAssociate>>);

然后我定义了一个服务

function TLookupService.GetLookupFor(aModelTypeInfo : PTypeInfo) : IInterface
begin
    Result := FContainer.Resolve(SomeHowGetTypeOf(ILookupView<aModelTypeInfo>).AsInterface;
end

问题在于我无法使用TLookupService.GetLookupFor<T>,但我必须使用TLookupService.GetLookupFor(aTypeInfo : TTypeInfo)

这是因为接口不能包含通用成员。

如果我定义了一个服务接口,那么我会收到编译错误

ILookupService = interface
   GetLookupFor<T> : ILookupView<T>; // compilation error
end;

所以我必须在这里移动通用参数

ILookupService<T> = interface
   GetLookup : ILookupView<T>; 
end;

但是这意味着我必须为我想要使用的每种类型的查找都有一个ILookupService实例:

MyForm = class(TForm)

fAssociateLookupService : ILookupService<TAssociate>;
fMandateLookupService : ILookupService<TMandate>;
fTaskLookupService : ILookupService<TTask>

end;

而不是

MyForm = class(TForm)
   fLookupService: ILookupService;
end;

这就是为什么我想要定义一个像这样的界面

ILookupService = interface
   GetLookupFor(aType : PTypeInfo) : IInterface; 
end;

所以我可以使用

procedure TMyForm.DoIt
var
  aLookup : ILookupView<TMandate>;
begin
    aLookup := fLookupService.GetLookupFor(TypeInfo(TMandate)) as ILookupView<TMandate>;
end;

1 个答案:

答案 0 :(得分:8)

我不认为T可以是动态的, 编译器需要知道T在编译时的类型。

编译器为每种使用的T类型创建一个泛型类。 例如:

IMyInterface<TObjectType1>
IMyInterface<TObjectType2>

它不会在运行时创建它们,它们是在编译时创建的。