In the question here a method for creating a compatible TValue to use with SetValue is shown. I'm trying to make a generic version of this, to use RTTI to store a class into an INI file. This is my cut down code:
procedure TMyClass.LoadRTTI(xObject: TObject);
var
LContext: TRttiContext;
LClass: TRttiInstanceType;
xField : TRttiField;
szNewValue : String;
xValue : TValue;
begin
LContext := TRttiContext.Create;
LClass := LContext.GetType(xObject.ClassType) as TRttiInstanceType;
for xField in LClass.GetDeclaredFields do
begin
szNewValue := IniFile.ReadString(szSection, xField.Name, '');
if szNewValue <> '' then // emumerated will be '0' (zero) as that is what GetValue.AsString returns
begin
case xField.FieldType.TypeKind of
tkEnumeration: xValue := StrToIntDef(szNewValue, xField.GetValue(xObject).AsOrdinal);
end;
xField.SetValue(xObject, xValue); // FAILS HERE with 'Invalid calss typecast
end;
end;
end;
In the answer referenced, the solution was to get the value using the TValue.From() method, but that appears to require a variable of the appropriate type. I don't have such a type as my code doesn't know what it is.
I am seeking an example of a generic way to obtain a value in a string from the RTTI, and put it back again afterward. I've not found a good tutorial that covers this yet.
You must get an instance to the TValue
to set before assing a value, and then convert the string to the enumerated value using the GetEnumValue
function
Try this code :
procedure TMyClass.LoadRTTI(xObject: TObject);
var
LContext: TRttiContext;
LClass: TRttiInstanceType;
xField : TRttiField;
szNewValue : String;
xValue : TValue;
begin
LContext := TRttiContext.Create;
LClass := LContext.GetType(xObject.ClassType) as TRttiInstanceType;
for xField in LClass.GetDeclaredFields do
begin
szNewValue := IniFile.ReadString(szSection, xField.Name, '');
if szNewValue <> '' then // emumerated will be '0' (zero) as that is what GetValue.AsString returns
begin
case xField.FieldType.TypeKind of
tkEnumeration:
begin
//get the instance to the TValue to set
xValue:=xField.GetValue(xObject);
//convert the data to a valid TValue
xValue:=TValue.FromOrdinal(xValue.TypeInfo,GetEnumValue(xValue.TypeInfo,szNewValue));
end;
end;
//assign the new value from the TValue
xField.SetValue(xObject, xValue);
end;
end;
end;
Here is some example code showing how do this:
var
V : TValue;
OrdValue : Integer;
C : TRttiContext;
F : TRttiField;
lTypeInfo : PTypeInfo;
begin
// Pick a Enumerated Field
F := C.GetType(TForm).GetField('FFormStyle');
// Get the TypeInfo for that field
lTypeInfo := F.FieldType.Handle;
// Setting TValue from an Enumeration Directly.
V := TValue.From(FormStyle);
ShowMessage(V.ToString);
// Setting TValue from the ordinal value of a Enumeration
OrdValue := ord(FormStyle);
V := TValue.FromOrdinal(lTypeInfo,OrdValue);
ShowMessage(V.ToString);
// Setting TValue from the String Value of an enumeration.
OrdValue := GetEnumValue(lTypeInfo,'fsStayOnTop');
V := TValue.FromOrdinal(lTypeInfo,OrdValue);
ShowMessage(V.ToString);
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With