Delphi:RTTI 和 TObjectList

发布于 2024-08-27 12:03:25 字数 1277 浏览 7 评论 0原文

基于对早期的一个答案post,我正在研究以下设计的可能性

TChildClass = class(TObject)
private
  FField1:  string;
  FField2:  string;
end;

TMyClass = class(TObject)
private
  FField1:  TChildClass;
  FField2:  TObjectList<TChildClass>;
end;

现在,在现实世界中,TMyClass 将有 10 个这样的不同列表,因此我希望能够使用 RTTI 来处理这些列表。但是,我对此类的其他字段不感兴趣,因此我需要检查某个字段是否是某种 TObjectList。这是我到目前为止所得到的:

procedure InitializeClass(RContext: TRttiContext; AObject: TObject);
var
  ROwnerType:   TRttiType;
  RObjListType: TRttiType;
  RField:       TRttiField;
  SchInf:       TSchemaInfoDetail;
begin
ROwnerType := RContext.GetType(AObject.ClassInfo);
RObjListType := RContext.GetType(TObjectList<TObject>);
for RField in ROwnerType.GetFields do begin
  // How do I check if the type of TMyClass.FField2 (which is TObjectList<TChildClass>) is some sort of TObjectList?
end;

显然,RField.FieldType <> RObjListType.FieldType。不过,他们确实有一些关系,不是吗?为了使 RField.FieldType 很可能实际上是一个 TObjectList 而对常见功能进行非常复杂的检查,这似乎很可怕(而且是错误的!)。

老实说,我对泛型很不舒服,所以这个问题可能很天真。然而,我非常乐意学习。上述解决方案是否可以实施?蒂亚!

Based on one answer to an earlier post, I'm investigating the possibility of the following design

TChildClass = class(TObject)
private
  FField1:  string;
  FField2:  string;
end;

TMyClass = class(TObject)
private
  FField1:  TChildClass;
  FField2:  TObjectList<TChildClass>;
end;

Now, in the real world, TMyClass will have 10 different lists like this, so I would like to be able to address these lists using RTTI. However, I'm not interested in the other fields of this class, so I need to check if a certain field is some sort of TObjectList. This is what I've got so far:

procedure InitializeClass(RContext: TRttiContext; AObject: TObject);
var
  ROwnerType:   TRttiType;
  RObjListType: TRttiType;
  RField:       TRttiField;
  SchInf:       TSchemaInfoDetail;
begin
ROwnerType := RContext.GetType(AObject.ClassInfo);
RObjListType := RContext.GetType(TObjectList<TObject>);
for RField in ROwnerType.GetFields do begin
  // How do I check if the type of TMyClass.FField2 (which is TObjectList<TChildClass>) is some sort of TObjectList?
end;

Clearly, RField.FieldType <> RObjListType.FieldType. However, they do have some relation, don't they? It seems horrible (and wrong!) to make a very elaborate check for common functionality in order to make it highly probable that RField.FieldType is in fact a TObjectList.

To be honest, I am quite uncomfortable with generics, so the question might be very naïve. However, I'm more than happy to learn. Is the above solution possible to implement? TIA!

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

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

发布评论

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

评论(2

望笑 2024-09-03 12:03:26

每个通用实例化都是唯一的,并且与 RTTI 方面的其他实例化没有关系。由于 Delphi 无法在运行时实例化泛型类型,因此没有与 .NET 的 GetGenericTypeDefinition 等价的函数。您能做的最好的事情就是查看类型的形状 - 例如,它是否实现了 GetEnumeratorAdd 等。

这也可以足够灵活来处理一般集合类型,而不是只是从 TObjectList 实例化的。 C# 对其集合初始值设定项执行类似的操作 - 它查找 Add 方法并插入对其的调用:

http://msdn.microsoft.com/en-us/library/bb384062.aspx

Every generic instantiation is unique and has no relationship with other instantiations with respect to RTTI. Because Delphi can't instantiate generic types at runtime, there's no equivalent to e.g. .NET's GetGenericTypeDefinition. The best you can do is look at the shape of the type - e.g. does it implement GetEnumerator, Add etc.

This could also be flexible enough to handle general collection types, not just ones instantiated from TObjectList<T>. C# does something similar with its collection initializers - it looks for an Add method and inserts calls to it:

http://msdn.microsoft.com/en-us/library/bb384062.aspx

半仙 2024-09-03 12:03:26

Delphi 可以在运行时实例化泛型类型。
问题是,泛型类型通常不保存在运行时信息中。如果您持有特定类型的全局变量(在您的情况下为 TObjectList),请在初始化部分实例化(并释放)它,该特定类的运行时信息不会被链接器删除,您将能够实例化稍后动态地进行。 (您需要提供类的完整限定名称,context.findType() 才能正常工作。)
我花了一些时间弄清楚如何做到这一点,我对此绝对不满意,但由于我还没有找到其他方法,所以我现在必须处理它。如果有人知道更好的方法,请告诉我。

Delphi can instantiate generic types at runtime.
The problem is, that generic types are generally not held in the runtime information. If you hold a global var of the specific type (TObjectList< TChildClass > in your case), instantiate (and free) it in initialization section the runtime information of that specific class wont be stripped by the linker and you will be able to instantiate it dynamically later. (You need to provide the full qualified name of the classes for context.findType() to work properly.)
I spent some time figuring out how this can be done and I am definitely not happy with it, but since I haven't found another way I have to deal with it for now. If anybody knows a better way to do let me know.

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