Delphi 基于无约束泛型类型创建对象实例
我有一个无约束的泛型原子类型,它实现了一个初始值设定项(详细信息见我的文档)Delphi 基于无约束泛型类型创建对象实例,delphi,generics,Delphi,Generics,我有一个无约束的泛型原子类型,它实现了一个初始值设定项(详细信息见我的文档) 类型 原子=类 类型TFactory=对函数的引用:T; 类函数初始化(变量存储:T;工厂:TFactory):T; 结束; 现在我想编写一个简化的初始化函数,它将从T获取类型信息(前提是typeof(T)是tkClass)并使用默认构造函数创建新实例(必要时) 可悲的是,这失败了: class function Atomic<T>.Initialize(var storage: T): T; begin
类型
原子=类
类型TFactory=对函数的引用:T;
类函数初始化(变量存储:T;工厂:TFactory):T;
结束;
现在我想编写一个简化的初始化函数,它将从T获取类型信息(前提是typeof(T)是tkClass)并使用默认构造函数创建新实例(必要时)
可悲的是,这失败了:
class function Atomic<T>.Initialize(var storage: T): T;
begin
if not assigned(PPointer(@storage)^) then begin
if PTypeInfo(TypeInfo(T))^.Kind <> tkClass then
raise Exception.Create('Atomic<T>.Initialize: Unsupported type');
Result := Atomic<T>.Initialize(storage,
function: T
begin
Result := TClass(T).Create; // <-- E2571
end);
end;
end;
类函数原子初始化(var存储:T):T;
开始
如果未分配(点(@storage)^),则开始
如果PTypeInfo(TypeInfo(T))^.kindtkclass那么
引发异常.Create('Atomic.Initialize:Unsupported type');
结果:=原子。初始化(存储,
功能:T
开始
结果:=TClass(T).Create;//可用于获取类引用:
Result := T(GetTypeData(PTypeInfo(TypeInfo(T)))^.ClassType.Create);
在Delphi XE2中(希望在下一版本中),您可以执行以下操作:
var
xInValue, xOutValue: TValue;
xInValue := GetTypeData(PTypeInfo(TypeInfo(T)))^.ClassType.Create;
xInValue.TryCast(TypeInfo(T), xOutValue);
Result := xOutValue.AsType<T>;
var
xInValue,xOutValue:TValue;
xInValue:=GetTypeData(PTypeInfo(TypeInfo(T))^.ClassType.Create;
TryCast(TypeInfo(T),xOutValue);
结果:=xOutValue.AsType;
(OmniThreadLibrary论坛中使用的cjsalamon
发现了这种相当绕开的方式:)您可以使用新的DelphiRtti
来执行此任务。给定解决方案的缺点是,如果构造函数未命名为Create,它将无法工作。如果您需要使它一直工作,只需枚举您的类型方法,检查它是否是构造函数,是否有0个参数,然后调用它。在Delphi XE中工作。示例代码:
class function TTest.CreateInstance<T>: T;
var
AValue: TValue;
ctx: TRttiContext;
rType: TRttiType;
AMethCreate: TRttiMethod;
instanceType: TRttiInstanceType;
begin
ctx := TRttiContext.Create;
rType := ctx.GetType(TypeInfo(T));
AMethCreate := rType.GetMethod('Create');
if Assigned(AMethCreate) and rType.IsInstance then
begin
instanceType := rType.AsInstance;
AValue := AMethCreate.Invoke(instanceType.MetaclassType, []);// create parameters
Result := AValue.AsType<T>;
end;
end;
类函数TTest.CreateInstance:T;
变量
AValue:TValue;
ctx:trtti上下文;
rType:trttype;
方法:trtti法;
instanceType:trttInstanceType;
开始
ctx:=TRttiContext.Create;
rType:=ctx.GetType(TypeInfo(T));
创建:=rType.GetMethod('Create');
如果已分配(创建)和rType.IsInstance,则
开始
instanceType:=rType.AsInstance;
AValue:=创建.Invoke(instanceType.MetaclassType,[]);//创建参数
结果:=AValue.AsType;
结束;
结束;
更新的解决方案:
class function TTest.CreateInstance<T>: T;
var
AValue: TValue;
ctx: TRttiContext;
rType: TRttiType;
AMethCreate: TRttiMethod;
instanceType: TRttiInstanceType;
begin
ctx := TRttiContext.Create;
rType := ctx.GetType(TypeInfo(T));
for AMethCreate in rType.GetMethods do
begin
if (AMethCreate.IsConstructor) and (Length(AMethCreate.GetParameters) = 0) then
begin
instanceType := rType.AsInstance;
AValue := AMethCreate.Invoke(instanceType.MetaclassType, []);
Result := AValue.AsType<T>;
Exit;
end;
end;
end;
类函数TTest.CreateInstance:T;
变量
AValue:TValue;
ctx:trtti上下文;
rType:trttype;
方法:trtti法;
instanceType:trttInstanceType;
开始
ctx:=TRttiContext.Create;
rType:=ctx.GetType(TypeInfo(T));
例如,在rType.GetMethods中创建
开始
如果(AMethCreate.IsConstructor)和(Length(AMethCreate.GetParameters)=0),则
开始
instanceType:=rType.AsInstance;
AValue:=create.Invoke(instanceType.MetaclassType,[]);
结果:=AValue.AsType;
出口
结束;
结束;
结束;
这样称呼它:
var
obj: TTestObj;
begin
obj := TTest.CreateType<TTestObj>;
var
obj:tobj;
开始
obj:=TTest.CreateType;
如果我没有弄错,泛型类型“T
”是一个类。在这种情况下,只需声明:
Atomic< T: class > = class
原子=class
而不是公寓
Atomic< T > = class
原子=类
这将告诉编译器T
是一种类类型,因此您可以使用构造函数和类类型的所有其他特性,而无需任何额外的解决方法
如果我对基本假设的理解是错误的,我很抱歉。如果我将结果转换回T(我已经修复了您的示例),它将完全按照我的意愿工作-谢谢!欢迎!是的,有必要进行类型转换。结果()表明此代码调用了错误的构造函数。“更新的解决方案”Linas在这方面做得更好。谢谢,但是XE2 Update 2的核心问题是,如果T没有标记“类”约束,TypeInfo(T)将无法编译。我不知道这是一个“特性”还是一个bug?我不确定,但恐怕这是一个特性。它看起来像我关于TypeInfo(T)的陈述没有在XE2更新2上编译是错误的。对不起:(我已经用在XE2更新2上工作的解决方案更新了TOndrej的答案。不,T只是有时是一个类,其他时候不是。
Atomic< T > = class