2010-04-01 67 views
4

基于一个答案到一个较早的post,我调查了以下设计的可能性,现在德尔福:RTTI和TObjectList <TObject>

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!

+0

谢谢梅森。我认为将此标记为2010年的问题有点矫枉过正。 – conciliator 2010-04-01 19:15:37

回答

5

每个泛型实例都是唯一的,并且与其他实例在RTTI方面没有关系。因为Delphi不能在运行时实例化泛型,所以没有与.NET的GetGenericTypeDefinition。你可以做的最好的是看看这个类型的形状 - 例如它实现GetEnumeratorAdd

这也可能是足够的灵活性来处理一般集合类型,而不仅仅是那些从TObjectList<T>实例化。 C#中有类似的功能,其集合初始化 - 它寻找一个Add方法和插入调用它:

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

+0

谢谢巴里!我想我会在你指出的时候寻找一个Add-method。 +1 :) – conciliator 2010-04-01 11:07:19

1

德尔福可以在运行时实例化泛型类型。 问题是,通用类型通常不会保留在运行时信息中。如果你持有一个特定类型的全局变量(TObjectList < TChildClass>在你的情况下),在初始化部分实例化(并释放)它,该特定类的运行时信息不会被链接器剥离,你将能够实例化它稍后动态。 (你需要提供context.findType()类的完整限定名称才能正常工作。) 我花了一些时间弄清楚如何做到这一点,我绝对不满意它,但由于我没有发现另一种方式,我现在必须处理它。如果有人知道更好的方式让我知道。