Delphi编程中的Enums vs Const vs Class Const

时间:2008-12-19 21:19:00

标签: delphi

我在ClientDataSet中有一个整数字段,我需要比较一些值,如下所示:

我可以使用const

const
  mvValue1 = 1;
  mvValue2 = 2;

if ClientDataSet_Field.AsInteger = mvValue1 then

或枚举

TMyValues = (mvValue1 = 1, mvValue2 = 2);

if ClientDataSet_Field.AsInteger = Integer(mvValue1) then

或类const

TMyValue = class
const
   Value1 = 1;
   Value2 = 2;
end;

if ClientDataSet_Field.AsInteger = TMyValues.Value1 then

我喜欢类const方法,但似乎不是delphi的方式,所以我想知道你的想法

6 个答案:

答案 0 :(得分:12)

声明:

type
  TMyValues = class
    type TMyEnum = (myValue1, myValue2, myValue3, myValue4);
    const MyStrVals: array [TMyEnum] of string =
      ('One', 'Two', 'Three', 'Four');
    const MyIntVals: array [TMyEnum] of integer =
      (1, 2, 3, 4);
  end;

用法:

if ClientDataSet_Field.AsInteger = TMyValues.MyIntVals[myValue1] then

演员通常是我的最后选择。

答案 1 :(得分:11)

我不会说类consts不是Delphi方式。最近他们刚刚将它们介绍给Delphi,你在互联网上发现的很多书籍和文章都是在它们推出之前编写的,因此你不会看到它们被广泛使用。许多Delphi开发人员(我会说大多数人)会在Delphi开始使用之前开始使用Delphi,因此他们不是第一个想到的东西。

答案 2 :(得分:4)

要考虑的一点是向后兼容性 - 类常量对于Delphi来说是相对较新的,所以如果你的代码必须与之前的版本共享而不是它们的版本。

我通常使用枚举类型,与你的不同之处在于我的第一个枚举通常是一个'undefined'项来表示int字段中的NULL或0。

TmyValues = (myvUndefined, myvDescription1, myvDescription2)

if ClientDataSet_Field.AsInteger = Ord(myvDescription1) then...

使用一点Jim McKeeth的答案 - 如果您需要向用户显示文本可查看的版本,或者如果您需要将他们选择的文本转换为枚举类型,那么阵列就可以派上用场了类型:

const MYVALS: array [TmyValues ] of string = ('', 'Description1', 'Description2');

然后,您可以使用实用程序函数来设置/获取字符串中的枚举类型:

Function MyValString(const pMyVal:TmyValues):string;
begin
  result := MYVALS[Ord(pMyVal)];
end;

Function StringToMyVal(const pMyVal:String):TMyValues;
var i:Integer;
begin
  result := myvUndefined;
  for i := Low(MYVALS) to High(MYVALS) do
  begin
    if SameText(pMyVal, MYVALS[i]) then
    begin
      result := TMyValues(i);
      break;
    end;
  end;
end;

继续......您可以使用分散例程来设置组合/列表框:

Procedure SetList(const DestList:TStrings);
begin
  DestList.Clear;
  for i := Low(MYVALS) to High(MYVALS) do
  begin
    DestList.Insert(MYVALS[i]);
  end;
end;

在代码中:SetList(Combo1.Items)或SetList(ListBox1.Items)..

然后,如果你看到这里的模式......围绕你的枚举的有用的实用函数,那么你将所有东西添加到它自己的类中,并将这个类放入它自己的名为MyValueEnumeration或whaterver的单元中。您最终会将此枚举周围的所有代码放在一个位置,并根据需要不断添加实用程序功能。如果你保持单位清洁 - 不要混合其他不相关的功能,那么它将对与该枚举相关的所有项目保持非常方便。

随着时间的推移你会看到更多模式,你会反复使用相同的功能,你会再次构建一个更好的捕鼠器。

答案 3 :(得分:1)

这么多选择! :-)我更喜欢枚举,并按照你的描述定期使用它们。我喜欢的部分之一是我可以使用“for”循环。我也使用类常量,但更喜欢枚举(甚至私有枚举),这取决于我想要实现的目标。

TMyType=class
private const    // d2007 & later i think
  iMaxItems=1;   // d2007 & later i think
private type     // d2007 & later i think
  TMyValues = (mvValue1 = 1, mvValue2 = 2);     // d2007 & later i think
private
public
end;

答案 4 :(得分:1)

使用常量时,我​​建议在数据类型为数字浮点数时指定类型。

如果类型不匹配,Delphi和其他语言将无法始终正确评估值...

TMyValue = class
const
   // will not compare correctly to float values.
   Value1 = 1; // true constant can be used to supply any data type value
   Value2 = 2; // but should only be compared to similar data type

   // will not compare correctly to a single or double.
   Value3 = 3.3; // default is extended in debugger 

   // will not compare correctly to a single or extended.
   Value1d : double = Value1; // 1.0
   Value2d : double = Value2; // 2.0
end;

将if()和while()语句中的浮点值与同一数据类型的值进行比较,因此最好定义用于任何比较语句的float类型的临时或全局变量(=< >)

与相同的浮点数据类型相比,这种格式对于任何编程语言中的比较运算符更可靠,不仅在Delphi中,而且在任何编程语言中,定义的浮点类型从变量变为常量。

一旦你指定了一个类型,Delphi将不允许你使用该变量来提供另一个常量,所以真正的常量可以提供任何相关的数据类型,但不能用于循环和if语句的比较,除非它们被分配和与整数值进行比较。

***注意:将值从一个浮点类型转换为另一个浮点类型可能会更改您输入的值以进行比较,因此请在执行此操作时使用单元测试进行验证。

令人遗憾的是,Delphi不允许像......这样的枚举格式。     TController:Integer =(NoController = 0,ncpod = 1,nextwave = 2);

或强制使用类型名称来访问枚举值。

或允许类常量在调用中用作参数默认值,如...     function getControllerName(Controller:TController = TController.NoController):string;

但是,提供两种访问类型的更加谨慎的方法是将枚举放在类中。

 TController = class
  //const
     //NoController : Integer = 1;
     //ncpod : Integer = 2;
     //nextwave : Integer = 3;

  type
     Option = (NoController = 0, ncpod = 1, nextwave = 2);

  public
    Class function Name( Controller : Option = NoController) : string; static;
 end;

 implementation

 class function TController.Name( Controller : Option = NoController) : string;
 begin
    Result := 'CNC';
    if (Controller = Option.nextwave) then
       Result := Result + ' Piranha'
    else if (Controller = Option.ncpod) then
       Result := Result + ' Shark';

    Result := Result + ' Control Panel';
 end;

这种方法将有效地隔离值,提供静态方法并允许使用for()循环访问值。

从浮动函数访问值将是这样的......

 using TControllerUnit;

 function getName( Controller : TController.Option = TController.Option.NoController) : string;

 implementation

 function getName( Controller : TController.Option = TController.Option.NoController) : string;
 begin
   Result := 'CNC';
   if (Controller = TController.Option.nextwave) then
       Result := Result + ' Piranha'
   else if (Controller = TController.Option.ncpod) then
       Result := Result + ' Shark';

   Result := Result + ' Control Panel';
 end;

答案 5 :(得分:0)

您没有想到的一个选项是在数据库中使用查找表,然后您可以检查数据库中的字符串。

例如

 Select value, Description from tbl_values inner join tbl_lookup_values where tbl_values.Value = tbl_lookup_values.value

if ClientDataSet_Field.AsString = 'ValueIwant' then