将泛型类型的成员转换为TObject?

时间:2011-02-22 07:37:37

标签: delphi generics casting delphi-2010

我目前正在考虑一种情况,我想要一个在其项目 IF 上调用Free的泛型类,这些类是对象类型。所以我尝试了以下内容:

if (PTypeInfo (TypeInfo (T)).Kind = tkClass) then
  begin
  RttiType := RttiContext.GetType (TypeInfo (T));
  FreeMethod := RttiType.GetMethod ('Free');
  if (FreeMethod <> nil) then
    FreeMethod.Invoke (FInstance, []);
  end;

不幸的是最后一行没有编译,这并不奇怪,因为类型不匹配。问题是:我可以编译吗?我尝试转换为Pointer然后转到TObject,但这给了我一个无效的类型转换错误。有没有办法让FInstance : T加入TObject引用,然后我可以传递给Invoke

或者还有其他方法可以达到我的目的吗?请注意,重点是获取此类中的所有内容,因此我不想创建只接受对象的TObjectMyClass

感谢您的帮助。

4 个答案:

答案 0 :(得分:5)

这不够吗?

if PTypeInfo(TypeInfo(T))^.Kind = tkClass then
  TObject(FInstance).Free;

答案 1 :(得分:2)

直接转换为TObject似乎在Delphi 2010中有效:

FreeMethod.Invoke (TObject(FInstance), []);

完整示例:

implementation

uses TypInfo, Rtti;

{$R *.dfm}

type
  TTest<T> = class
    FInstance : T;
    procedure F;
  end;

procedure TForm1.FormCreate(Sender: TObject);
var
  O : TTest<TObject>;
begin
  O := TTest<TObject>.Create;
  O.FInstance := TStringList.Create;
  O.F;
  O.Free;
end;

{ TTest<T> }

procedure TTest<T>.F;
var
  RttiType : TRttiType;
  FreeMethod : TRttiMethod;
  RttiContext : TRttiContext;
begin
  if (PTypeInfo (TypeInfo (T)).Kind = tkClass) then
  begin
    RttiType := RttiContext.GetType (TypeInfo (T));
    FreeMethod := RttiType.GetMethod ('Free');
    if (FreeMethod <> nil) then
      FreeMethod.Invoke (TObject(FInstance), []);
  end;
end;

答案 2 :(得分:2)

这给我带来了糟糕的设计。泛型的一个要点是摆脱像这样的动态类型决策。

如果你真的在使用泛型特性,那么让我更有意义的是让一个受限制的类型参数的子类只占用TObject个后代。由于您必须静态地决定如何实例化泛型类,因此当TMyObjectClass是一个类时使用T并在其他地方使用TMyClass毫无疑问。

如果单个容器需要同时包含对象和非对象,我猜你会被迫采取你正在采取的方法。但如果情况并非如此,那么我觉得有点不对劲。

答案 3 :(得分:1)

实际上,我自己就找到了答案。 TValue.From可以解决问题:

if (PTypeInfo (TypeInfo (T)).Kind = tkClass) then
  begin
  RttiType := RttiContext.GetType (TypeInfo (T));
  FreeMethod := RttiType.GetMethod ('Free');
  if (FreeMethod <> nil) then
    FreeMethod.Invoke (TValue.From <T> (FInstance), []);
  end;