Delphi:RTTI和TObjectList<TObject>

4

根据早期帖子中的一个答案,我正在调查以下设计的可能性。

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,制作非常复杂的公共功能检查似乎很可怕(也很错误!)。

老实说,我对泛型感到非常不舒服,所以这个问题可能非常幼稚。但是,我非常愿意学习。上述解决方案是否可行?TIA!


谢谢Mason。我觉得标记成2010年的问题可能有点过了。 - conciliator
2个回答

6
每个泛型实例都是唯一的,与其他实例在RTTI方面没有关系。因为Delphi不能在运行时实例化泛型类型,所以没有相当于.NET的GetGenericTypeDefinition。最好的方法是查看类型的形状-例如它是否实现了GetEnumeratorAdd等。
这也可以足够灵活地处理一般的集合类型,而不仅仅是从TObjectList<T>实例化的类型。C#使用其集合初始化程序执行类似操作-它查找Add方法并插入调用: http://msdn.microsoft.com/en-us/library/bb384062.aspx

谢谢你,Barry!我想我会像你说的那样寻找一个Add方法。+1 :) - conciliator

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接