delphi – 基于非约束泛型类型创建对象实例

前端之家收集整理的这篇文章主要介绍了delphi – 基于非约束泛型类型创建对象实例前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有无约束的通用类型Atomic,它实现一个初始化器(在我的 previous question中的细节).
type
  Atomic<T> = class
    type TFactory = reference to function: T;
    class function Initialize(var storage: T; factory: TFactory): T;
  end;

现在我想编写简化的初始化函数,它将从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类型参数’T’没有类或接口约束.

我如何欺骗编译器创建T类的实例?

解决方法

您可以使用新的Delphi Rtti来完成此任务.给定解决方案的缺点是,如果构造函数未命名为Create,则它将无法正常工作.如果你需要让它一直工作,只需枚举你的类型方法,检查它是否是一个构造函数,并有0个参数,然后调用它.在德尔福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>;

猜你在找的Delphi相关文章