[英]Creating object instance based on unconstrained generic type
我有一个不受约束的泛型Atomic类型,它实现了一个初始化程序(在上一个问题中有详细介绍)。
type
Atomic<T> = class
type TFactory = reference to function: T;
class function Initialize(var storage: T; factory: TFactory): T;
end;
现在,我想编写简化的Initialize函数,该函数将从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;
编译器报告错误E2571 Type parameter 'T' doesn't have class or interface constraint
。
如何欺骗编译器创建类T的实例?
您可以使用GetTypeData
获取类引用:
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>;
(此相当的回避方式被使用发现cjsalamon
在OmniThreadLibrary论坛: 在OtlSync XE2错误 。)
您可以使用新的Delphi Rtti
来完成此任务。 给定解决方案的缺点是,如果构造函数未命名为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;
更新的解决方案:
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;
并这样称呼它:
var
obj: TTestObj;
begin
obj := TTest.CreateType<TTestObj>;
如果我做对了,则通用类型“ T
”是一个类。 在这种情况下,只需声明:
Atomic< T: class > = class
而不是单位
Atomic< T > = class
这将告诉编译器T
是一个类类型,因此您将能够使用构造函数以及类类型的所有其他功能,而无需任何其他解决方法。
如果在基本假设中我的理解是错误的,我深表歉意。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.