【问题标题】:How to change my code to get the correct enumerate name value?如何更改我的代码以获得正确的枚举名称值?
【发布时间】:2016-03-12 22:23:21
【问题描述】:

我正在尝试使用 RTTI 获取枚举名称值。

我的目标是使用字符串值从 Enum2(iterator) 中选定的枚举名称值中获取 Enum1(Tsex) 中相应的枚举名称值。

这是我已经实现的代码。我正在使用 Delphi 7。

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs,typinfo;

type

 Tsex = (homme,femme);
 iterator = (H,F);

TForm1 = class(TForm)
  procedure FormShow(Sender: TObject);
private
 { Déclarations privées }
 public
 { Déclarations publiques }
end;

var
  Form1: TForm1;

implementation

 {$R *.dfm}


 procedure TForm1.FormShow(Sender: TObject);
  var
    i : integer;
    OT: Tsex;
    FT: iterator;
 begin
   i:=0;
   OT := Low(Tsex);
   for FT := Low(iterator) to High(iterator) do
     if GetEnumName(TypeInfo(iterator), Ord(FT)) = 'F' then
     begin
       showmessage(GetEnumName(TypeInfo(Tsex), Ord(OT)));
     end;
     i:=i+1;
     OT:=Succ(OT);
   end;

当我使用H 作为字符串时,我得到homme,但是当我使用F 时,我也得到homme。但它必须是femme

【问题讨论】:

  • 在循环的每次迭代中,调试器告诉您OT 的值是什么?
  • 我服务的目的是什么?为什么有两种枚举类型?应该只有一个。不要为了拥有短名称和长名称而定义额外的枚举类型。为此使用 const 数组。
  • 我认为你可能错过的一点是,当你有一个枚举时,你可以调用枚举名称,就好像它是一个返回枚举值的函数一样,例如OT := TSex(i)。您只需要 FormShow 中的一个变量来执行您现在正在执行的操作。
  • @DavidHeffernan 这只是我得到的一个想法,我需要它来工作(自我挑战),我真正的目标是从数据库中读取我的数据库中只有枚举缩写的字符串( 'E','F') 但在我的表单中,我想在所有枚举或 F 值中获取所有 E 对应值。
  • 您提出的解决方案不是前进的方向。你真的不想要枚举名称 F 和 H。太短了。无论您遇到什么问题,这都不是解决方案。

标签: delphi enums delphi-7 rtti


【解决方案1】:

问题:

您的代码中的问题是您在for 之后缺少begin,这会导致在迭代完成后发生i 的递增和OT 的分配。

你需要改变的是:

var
  i : integer;
  OT: Tsex;
  FT: iterator;
begin
  i:=0;
  OT := Low(Tsex);
  for FT := Low(iterator) to High(iterator) do
  begin // <- Add begin here
    if GetEnumName(TypeInfo(iterator), Ord(FT)) = 'F' then
    begin
      showmessage(GetEnumName(TypeInfo(Tsex), Ord(OT)));
    end;
    i:=i+1;
    OT:=Succ(OT);
  end;
 end; // <- Add end; here

替代解决方案:

正如 David 所指出的,最好使用数组将另一组值映射到您的枚举。像这样:

type
 TSex = (homme, femme);

const
 SexDBValues: array [TSex] of string =
 ('H', 'F');

type
  TForm1 = class(TForm)
  procedure FormShow(Sender: TObject);
  private
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function GetMyEnumValue(const aDBValue: string): TSex;
var
  value: TSex;
begin
  for value := Low(TSex) to High(TSex) do
  begin
    if SameText(SexDBValues[value], aDBValue) then
    begin
      Result := value;
      Exit;
    end;
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
var
  value: TSex;
begin
  value := GetMyEnumValue('H');
  ShowMessage(GetEnumName(TypeInfo(TSex), Ord(value)));
end;

当你的枚举类型只包含两个值,并且将来不太可能有额外的值时,你可以使用旧的 if-else 运算符:

function GetMyEnumValue(const aDBValue: string): TSex;
begin
  if SameText(aDBValue, 'F') then
  begin
    Result := femme;
  end else
  begin
    Result := homme;
  end;
end;

简而言之,避免过度设计问题。

注意:我们使用string 来存储字符值并使用SameText 来比较它,因为它不区分大小写地比较文本。另外,它允许您比较多个字符的文本,如果将来您改变了对值在 DB 中的存储方式的想法。


建议:

我也建议您咨询Delphi Coding Style Guide

这似乎与问题无关,但遵循缩进的良好做法有助于避免此类问题。

关于命名类型和变量的指南也很重要。在其他情况下,它们同样会拯救你。

【讨论】:

  • 我喜欢你的回答。这是一个愚蠢的错误,单/复合块。你解释了这一点,然后继续说更多。干得好!
  • 谢谢,其实我是想效仿你的!
  • @quasoft 我知道这里禁止说谢谢,但我真的忍不住了,谢谢你的年度最佳答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多