Reputation: 13
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.
Upvotes: 1
Views: 1520
Reputation: 612784
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.
Upvotes: 5