'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