如何在Delphi中将常量字符串组合在一起

Re0*_*ess 11 delphi

我的应用程序使用字符串作为不同状态的项目可以在其生命中.

OPEN,ACTIVE,CLOSED,DELETE,

等等,此刻它们都被硬编码成代码

MyVar := 'OPEN';
Run Code Online (Sandbox Code Playgroud)

我正在努力改变它,因为它可能是一个维护问题,所以我想将它们全部改为常量,我打算这样做

MyVar := STATUS_OPEN;
Run Code Online (Sandbox Code Playgroud)

但我想把它们组合成一个像这样的数据结构

MyVar := TStatus.Open;
Run Code Online (Sandbox Code Playgroud)

在delphi 2007中执行此操作的最佳方法是什么?

我知道我可以为此创建一个记录,但是如何用值填充它,以便系统中的所有对象都可以使用它,而不必每次创建变量并填充值?

理想我希望有一个数据结构和值的中心位置,并且可以轻松访问它们(如TStatus.Open),而无需在每次使用它时将其分配给变量或创建对象.

我确信有一个简单的解决方案,我只是缺少.有任何想法吗?

Ond*_*lle 13

正如Jim所说,你可以使用类常量或枚举类型:

type
  TItemStatus = (isOpen, isActive, isClosed);
const
  ItemStatusStrings: array[TItemStatus] of string = ('Open', 'Active', 'Closed');
Run Code Online (Sandbox Code Playgroud)


Jim*_*Jim 12

请参阅http://edn.embarcadero.com/article/34324 ("自Delphi 7以来的新Delphi语言特性").

类常量可以很好地完成.从上面的链接:

type
    TClassWithConstant = class
      public 
        const SomeConst = 'This is a class constant';
    end;


 procedure TForm1.FormCreate(Sender: TObject);
 begin
   ShowMessage(TClassWithConstant.SomeConst);
 end;
Run Code Online (Sandbox Code Playgroud)


Dav*_*lor 8

我个人在几个大型关键任务数据处理平台上广泛使用了TOndrej的方法.枚举的好处是它们可以在应用程序中轻松传递,非常紧凑(有序类型),在case语句中完美地工作并且完全是类型安全的.后一点对于维护很重要,因为删除或更改枚举值将导致编译错误(一个好的想法恕我直言).

有些人需要注意这种方法:

  • 更改枚举值的声明顺序将foo bar enum-> string lookup数组.

  • 如果在case语句中使用枚举(一个很好的功能),请务必考虑添加的新值.我通常在case中添加一个else并在未知值上抛出异常.比落入案件要好得多.

如果您非常关心第一个问题,可以在查找数组中使用记录并在每个记录中包含枚举值,并从单元初始化中验证排序.这使我的培根在经常进行维护的关键任务系统中多次保存.此方法还可用于向每个值添加其他元数据(非常方便的功能).

祝你好运!

unit Unit1;

interface

type
  TItemStatusEnum = (isOpen, isActive, isClosed);

  TItemStatusConst = class
    class function EnumToString(EnumValue : TItemStatusEnum): string;
    property OPEN: string index isOpen read EnumToString;
    property CLOSED: string index isClosed read EnumToString;
    property ACTIVE: string index isActive read EnumToString;
  end;

var
  ItemStatusConst : TItemStatusConst;

implementation

uses
  SysUtils;

type
  TItemStatusRec = record
    Enum  : TItemStatusEnum;
    Value : string;
  end;

const
  ITEM_STATUS_LOOKUP : array[TItemStatusEnum] of TItemStatusRec =
    ((Enum: isOpen;   Value: 'OPEN'),
     (Enum: isActive; Value: 'ACTIVE'),
     (Enum: isClosed; Value: 'CLOSED'));

procedure ValidateStatusLookupOrder;
  var
    Status : TItemStatusEnum;
  begin
    for Status := low(Status) to high(Status) do
      if (ITEM_STATUS_LOOKUP[Status].Enum <> Status) then
        raise Exception.Create('ITEM_STATUS_LOOKUP values out of order!');
  end;

class function TItemStatusConst.EnumToString(EnumValue: TItemStatusEnum): string;
  begin
    Result := ITEM_STATUS_LOOKUP[EnumValue].Value;
  end;

initialization
  ValidateStatusLookupOrder;
end.
Run Code Online (Sandbox Code Playgroud)

更新:

感谢您的批评 - 您完全正确,因为我正在解决我认为问题背后的问题.下面是一个简单的方法,如果你可以忍受这个必须只在Delphi 2007或更高版本中工作的约束(可能在D2006中工作?).难以摆脱那些向后兼容的唠叨思想;)

type
  ItemStatusConst = record
    const OPEN   = 'OPEN';
    const ACTIVE = 'ACTIVE';
    const CLOSED = 'CLOSED';
  end;
Run Code Online (Sandbox Code Playgroud)

这种方法很简单,与Java或.Net应用程序中的方法类似.用法语义符合预期,可用于代码完成.一个很大的优点是常量的作用域是一个记录级别,因此不存在与单元作用域类型相冲突的其他定义的风险.

Sample usage:

    ShowMessage(ItemStatusConst.ACTIVE);
    ShowMessage(ItemStatusConst.CLOSED);
Run Code Online (Sandbox Code Playgroud)

为了好玩,我还修改了我之前的方法,直接解决了原始问题并得到了类似的结果.这次我使用了属性索引器的"模拟类属性"(见这里).这显然比记录方法更复杂,但保留了使用枚举值,集合,字符串的能力,并且还可以扩展以在需要时实现其他元数据功能.我相信这适用于德尔福版本,可以追溯到Delphi 5 IIRC.

我使用这种技术效果很好的一个例子是我在Delphi中创建的解析框架,用于处理完整的 IBM AFPDS打印数据流语法.这种灵活性是我喜欢在德尔福工作的原因 - 它就像一把瑞士军刀;)


eKe*_*ek0 1

您可以有一个记录类型的全局变量。记录类型必须为您拥有的每种状态都有一个字段。

您可以通过调用在该单元中声明的过程或函数来填充任何单元的初始化部分中的记录。您可以使用一个单元来专门完成这项工作,例如 StatusTypes.pas。

在接口部分,您可以声明如下内容:

type 
  TStatus = record
    OPEN: string;
  end;

var
  Status: TStatus;
Run Code Online (Sandbox Code Playgroud)