Reputation: 1665
How do I use RTTI to set an enumerated field's value ?
I.e.
type
TCPIFileStatus= (fsUnknown, fsProcessed);
TTest = class
FStatus: TCPIFileStatus;
end;
...
var
Data: TTest;
Ctx: TRttiContext;
Status : TCPIFileStatus;
begin
Data := TTest.Create;
Status := fsProcessed;
Ctx.GetType(Data.ClassType).GetField('FStatus').SetValue(Data, Status);
end;
I get "Invalid class typecast."
NB:I need to use RTTI because I will not always know the object type or field name at design time.
Upvotes: 4
Views: 3929
Reputation: 86
Another solution to this problem, in the case you don't know the exact enum type on your function but instead it's TypeInfo, is to use TValue's Make procedure.
procedure Make(AValue: NativeInt; ATypeInfo: PTypeInfo; out Result: TValue); overload; static;
Here is an example (From an XML config parser): This is later used for a TRTTIField/TRTTIProperty.SetValue()
function EnumNameToTValue(Name: string; EnumType: PTypeInfo): TValue;
var
V: integer;
begin
V:= GetEnumValue(EnumType, Name);
TValue.Make(V, EnumType, Result);
end;
Hope this helps you.
Upvotes: 4
Reputation: 17203
Use TValue.From generic method to obtain a compatible TValue value to pass to the SetValue method...
mmm... it's hard to get from words, better code:
type
TCPIFileStatus= (fsUnknown, fsProcessed);
TTest = class
FStatus: TCPIFileStatus;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
Data: TTest;
Ctx: TRttiContext;
Status : TCPIFileStatus;
AValue: TValue;
begin
Data := TTest.Create;
try
Status := fsProcessed;
Ctx.GetType(Data.ClassType).GetField('FStatus').SetValue(Data, TValue.From(Status));
Assert(Data.FStatus = Status, 'Something wrong on assigning status trough RTTI!');
finally
Data.Free;
end;
end;
Upvotes: 0
Reputation: 136391
you must pass a TValue
to the SetValue
method try using this code :
{$APPTYPE CONSOLE}
uses
Rtti,
SysUtils;
type
TCPIFileStatus= (fsUnknown, fsProcessed);
TTest = class
FStatus: TCPIFileStatus;
end;
var
Data : TTest;
Ctx : TRttiContext;
Status : TCPIFileStatus;
v : TValue;
begin
try
Data := TTest.Create;
try
Status := fsProcessed;
v:= v.From(status);
Ctx.GetType(Data.ClassType).GetField('FStatus').SetValue(Data, v);
// do your stuff
finally
Data.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Upvotes: 6