Rtti 访问记录结构中的字段、属性和调用方法

Rtti accessing fields, properties and invoke method in record structures

Rtti 访问记录结构中的字段、属性和调用方法。 我使用以下记录类型,来自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;      

但是对于记录,此代码不起作用

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;

我研究了网上所有的例子,但是没有用。

vType := vCtx.GetType(self);

GetType 方法期望传递一个指向类型信息的指针,或 class,但你传递了一个实例。相反,您应该像这样传递 class:

vType := vCtx.GetType(ClassType);

您不得将 TRttiContext 传递给 FreeAndNilTRttiContext 类型是一条记录。您不需要对该类型调用 Create。您不需要调用 Free

此外,您调用该方法的代码是错误的。

您的函数可能如下所示:

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;

该代码至少调用了该方法并检索了返回值。我会让你从那里拿走它。