Delphi RTTI SetValue для перечислений - PullRequest
4 голосов
/ 25 марта 2011

Как использовать RTTI для установки значения перечисляемого поля?

Т.е.

type
  TCPIFileStatus= (fsUnknown, fsProcessed);
  TTest = class
    FStatus: TCPIFileStatus; 
  end;
      ...
  var
    Data: TTest;
    Ctx: TRttiContext;
    Status : TCPIFileStatus;
  begin
    Data := TTest.Create;
    Status := fsProcessed;
    Ctx.GetType(Data.ClassType).GetField('FStatus').SetValue(Data, Status);
  end;

Я получаю "Недопустимый тип класса."
Примечание: мне нужно использовать RTTI, потому чтоЯ не всегда буду знать тип объекта или имя поля во время разработки.

Ответы [ 3 ]

6 голосов
/ 25 марта 2011

Вы должны передать TValue методу SetValue, попробуйте использовать этот код:

{$APPTYPE CONSOLE}
uses
  Rtti,
  SysUtils;


type
  TCPIFileStatus= (fsUnknown, fsProcessed);
  TTest = class
    FStatus: TCPIFileStatus;
  end;

  var
    Data   : TTest;
    Ctx    : TRttiContext;
    Status : TCPIFileStatus;
    v      : TValue;
begin
  try
    Data := TTest.Create;
    try
      Status := fsProcessed;
      v:= v.From(status); 
      Ctx.GetType(Data.ClassType).GetField('FStatus').SetValue(Data, v);

      // do your stuff
    finally
       Data.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
1 голос
/ 07 апреля 2012

Другое решение этой проблемы, в случае, если вы не знаете точный тип перечисления в вашей функции, но вместо этого это TypeInfo, заключается в использовании процедуры Make из TValue.

procedure Make(AValue: NativeInt; ATypeInfo: PTypeInfo; out Result: TValue); overload; static;

Вот пример (Из синтаксического анализатора XML): это позже используется для TRTTIField / TRTTIProperty.SetValue ()

function EnumNameToTValue(Name: string; EnumType: PTypeInfo): TValue;
var
  V: integer;

begin
  V:= GetEnumValue(EnumType, Name);
  TValue.Make(V, EnumType, Result);
end;

Надеюсь, это поможет вам.

0 голосов
/ 25 марта 2011

Используйте метод TValue.From для получения совместимого значения TValue для передачи в метод SetValue ...

ммм ... трудно получить из слов, лучше код:

type
  TCPIFileStatus= (fsUnknown, fsProcessed);
  TTest = class
    FStatus: TCPIFileStatus;
  end;

procedure TForm2.Button1Click(Sender: TObject);
var
  Data: TTest;
  Ctx: TRttiContext;
  Status : TCPIFileStatus;
  AValue: TValue;
begin
  Data := TTest.Create;
  try
    Status := fsProcessed;
    Ctx.GetType(Data.ClassType).GetField('FStatus').SetValue(Data, TValue.From(Status));
    Assert(Data.FStatus = Status, 'Something wrong on assigning status trough RTTI!');
  finally
    Data.Free;
  end;
end;
...