Delphi: RTTI and TObjectList<TObject>
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.FieldTyp开发者_如何学Ce <> 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!
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
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.
精彩评论