用于枚举的 Delphi RTTI SetValue

发布于 2024-10-26 07:07:19 字数 458 浏览 1 评论 0原文

如何使用 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,因为我在设计时并不总是知道对象类型或字段名称。

How do I use RTTI to set an enumerated field's value ?

I.e.

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;

I get "Invalid class typecast."
NB:I need to use RTTI because I will not always know the object type or field name at design time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

淡墨 2024-11-02 07:07:19

您必须将 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.

you must pass a TValue to the SetValue method try using this code :

{$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.
第七度阳光i 2024-11-02 07:07:19

如果您不知道函数的确切枚举类型而是 TypeInfo,则此问题的另一个解决方案是使用 TValue 的 Make 过程。

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;

希望这对您有帮助。

Another solution to this problem, in the case you don't know the exact enum type on your function but instead it's TypeInfo, is to use TValue's Make procedure.

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

Here is an example (From an XML config parser):
This is later used for a TRTTIField/TRTTIProperty.SetValue()

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

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

Hope this helps you.

诗酒趁年少 2024-11-02 07:07:19

使用 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;

Use TValue.From generic method to obtain a compatible TValue value to pass to the SetValue method...

mmm... it's hard to get from words, better code:

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;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文