Unfortunately, there is no RTTI generated for Generic parameters. The only way to discover the value of T
in a Generic container like TList<T>
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<System.string>'
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<TRttiType>;
...
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<TRttiType>;
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;
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…