I\'m implementing generic code for streaming arbitrary Delphi objects using RTTI, and in order to get this to work (more specifically, in order to get the loading part to wo
Unfortunately, there is no RTTI generated for Generic parameters. The only way to discover the value of T in a Generic container like TList is to get the TRttiType for the target field itself, call its ToString() method to get its class name as a string, and parse out the substring that is between the brackets. For example:
uses
..., System.StrUtils, System.Rtti;
var
Ctx: TRttiContext;
s: string;
OpenBracket, CloseBracket: Integer;
...
begin
...
s := Ctx.GetType(TTestClass).GetField('test_list').FieldType.ToString; // returns 'TList'
OpenBracket := Pos('<', s);
CloseBracket := PosEx('>', s, OpenBracket+1);
s := Copy(s, OpenBracket+1, CloseBracket-OpenBracket-1); // returns 'System.string'
// if multiple Generic parameters are present, they will be separated by commas...
...
end;
Once you have extracted the Generic parameter as a string, you can use TRttiContext.FindType() if you need to access the RTTI for that type.
With that said, the following code provides a bunch of RTTI helpers:
DSharp.Core.Reflection.pas (Google Code)
DSharp.Core.Reflection.pas (BitBucket)
Amongst other things, it defines a TRttiTypeHelper class helper that adds a GetGenericArguments() method to TRttiType:
TRttiTypeHelper = class helper for TRttiType
...
public
...
function GetGenericArguments: TArray;
...
end;
Internally, GetGenericArguments() uses the same technique I mention above. With it, you can do this instead:
uses
..., System.Rtti, DSharp.Core.Reflection;
var
Ctx: TRttiContext;
arr: TArray;
typ: TRttiType;
s: string;
...
begin
...
arr := Ctx.GetType(TTestClass).GetField('test_list').FieldType.GetGenericArguments;
typ := arr[0]; // returns RTTI for System.String
s := typ.ToString; // returns 'System.string'
...
end;