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

发布于 2024-10-18 15:52:00 字数 678 浏览 5 评论 0原文

我目前正在考虑一个场景,我想要一个泛型类,在其项目上调用 Free IF 这些项目属于对象类型。所以我尝试了以下操作:

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

感谢您的帮助。

I am currently thinking about a scenario where I want a generic class that calls Free on its items IF these are of an object type. So I tried the following:

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;

Unfortunately the last line does not compile, which is not surprising since the types do not match. The question is: can I get it to compile? I tried casting to Pointer and then to TObject but that gives me an invalid typecast error. Is there any way to get FInstance : T into a TObject reference that I can then pass to Invoke?

Or is there any other way to achieve what I want? Please note that the whole point is to get everything in this class, so I do not want to create a TObjectMyClass that just takes objects.

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ぃ弥猫深巷。 2024-10-25 15:52:00

这还不够吗?

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

Isn't this sufficient?

if PTypeInfo(TypeInfo(T))^.Kind = tkClass then
  TObject(FInstance).Free;
素染倾城色 2024-10-25 15:52:00

直接转换为 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;

Direct cast to TObject seems to work in Delphi 2010:

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

Full example:

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;
伴我心暖 2024-10-25 15:52:00

这对我来说有点糟糕的设计。泛型的要点之一是摆脱像这样的动态类型决策。

如果您确实使用泛型功能,那么对我来说,拥有一个带有类型参数且仅接受 TObject 后代的子类会更有意义。由于您必须静态地决定如何实例化泛型类,因此当 T 是一个类时使用 TMyObjectClass 并使用 TMyClass 其他地方。

我想如果单个容器需要包含对象和非对象,您将被迫采取您正在采取的方法。但如果情况并非如此,那么我就会感觉有些不对劲。

This smacks of poor design to me. One of the points of generics is to get away from dynamic type decisions like this.

If you really are using the generics feature then it would make more sense to me to have a subclass with a type parameter that is constrained take only TObject descendents. Since you have to decide statically how you are going to instantiate the generic class, it is no trouble whatsoever to use a TMyObjectClass when T is a class and to use TMyClass elsewhere.

I guess you'd be forced to take the approach you are taking if a single container needs to contain both objects and non-objects. But if that's not the case then something just feels off to me.

满地尘埃落定 2024-10-25 15:52:00

事实上,我自己刚刚找到了答案。 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;

Actually, I just found the answer myself. TValue.From does the trick:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文