'Rtti accessing fields, properties and invoke method in record structures
Rtti accessing fields, properties and invoke method in record structures. I use the following record types, is from site
type
Nullable<T> = record
public
FValue: T;
FHasValue: boolean;
procedure Clear;
function GetHasValue: boolean;
function GetValue: T;
constructor Create(AValue: T);
property HasValue: boolean read GetHasValue;
property Value: T read GetValue;
class operator Implicit(Value: Nullable<T>): T;
class operator Implicit(Value: T): Nullable<T>;
end;
type
TIntEx = Nullable<integer>;
TSmallintEx = Nullable<smallint>;
implementation
constructor Nullable<T>.Create(AValue: T);
begin
FValue := AValue;
FHasValue := false;
end;
function Nullable<T>.GetHasValue: boolean;
begin
Result := FHasValue;
end;
function Nullable<T>.GetValue: T;
begin
Result := FValue;
end;
class operator Nullable<T>.Implicit(Value: Nullable<T>): T;
begin
Result := Value.Value;
end;
class operator Nullable<T>.Implicit(Value: T): Nullable<T>;
begin
Result := Nullable<T>.Create(Value);
end;
But with a record this code doesn't work
type
[TableName('Record')]
TMyrecord = class(TPersistent)
private
FRecno: TIntEx;
FName: TStringEx;
protected
public
constructor Create();
destructor Destoy();
function GetSqlInsert(): string;
[SqlFieldName('recno')]
property Recno: TIntEx read FRecno write FRecno;
[SqlFieldName('Name')]
property Name: TStringEx read FName write FName;
end;
implementation
{ TMyrecord }
function TMyrecord.GetSqlInsert(): string;
var
vCtx: TRttiContext;
vType: TRttiType;
vProp: TRttiProperty;
vAttr: TCustomAttribute;
vPropValue: TValue;
vRecord: TRttiRecordType;
M: TRttiMethod;
tmpStr: String;
val: TValue;
begin
result := '';
vCtx := TRttiContext.Create;
try
vType := vCtx.GetType(self);
for vProp in vType.GetProperties do
for vAttr in vProp.GetAttributes do
if vAttr is SqlFieldName then
begin
if (vProp.IsReadable) and (vProp.IsWritable) and
(vProp.PropertyType.TypeKind = tkRecord) then
begin
vRecord := vCtx.GetType(vProp.GetValue(self).TypeInfo).AsRecord;
M := vRecord.GetMethod('GetValue');
if Assigned(M) then
vPropValue := (M.Invoke(vPropValue, []));
tmpStr := val.ToString;
end;
end;
finally
freeandnil(vCtx);
end;
end;
I studied all the examples on the internet but in vain.
Solution 1:[1]
vType := vCtx.GetType(self);
The GetType
method expects to be pass a pointer to type info, or a class, but you pass an instance. Instead you should pass the class like this:
vType := vCtx.GetType(ClassType);
You must not pass a TRttiContext
to FreeAndNil
. The TRttiContext
type is a record. You don't need to call Create
on that type. You don't need to call Free
.
Further more, your code to invoke the method is just wrong.
Your function might look like this:
function TMyrecord.GetSqlInsert(): string;
var
vCtx: TRttiContext;
vType: TRttiType;
vProp: TRttiProperty;
vAttr: TCustomAttribute;
vRecord: TValue;
M: TRttiMethod;
begin
vType := vCtx.GetType(ClassType);
for vProp in vType.GetProperties do
for vAttr in vProp.GetAttributes do
if vAttr is SqlFieldNameAttribute then
begin
if (vProp.IsReadable) and (vProp.IsWritable) and
(vProp.PropertyType.TypeKind = tkRecord) then
begin
vRecord := vProp.GetValue(self);
M := vProp.PropertyType.GetMethod('GetValue');
if Assigned(M) then
begin
Result := M.Invoke(vRecord, []).ToString;
exit;
end;
end;
end;
Result := '';
end;
That code does at least call the method and retrieve the returned value. I'll let you take it from there.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |