Delphi 是否有更简单的方法基于布尔值定义枚举类型? 概述

Delphi 是否有更简单的方法基于布尔值定义枚举类型? 概述,delphi,delphi-xe,Delphi,Delphi Xe,我不完全确定这个问题的措辞是否恰当,但我之前问过这个与此相关的问题: 我喜欢让代码尽可能地简短、最少和可读,这就是我认为一些代码可以写得更好的地方,但我遇到了问题 读取集合中的值的两种方法中的第一种方法示例: 漫长的道路: if (Delphi1 in IDECompatibility) then CheckListBox1.Checked[0] := True; if (Delphi2 in IDECompatibility) then CheckListBox1.Checked[1

我不完全确定这个问题的措辞是否恰当,但我之前问过这个与此相关的问题:

我喜欢让代码尽可能地简短、最少和可读,这就是我认为一些代码可以写得更好的地方,但我遇到了问题


读取集合中的值的两种方法中的第一种方法示例:

漫长的道路:

if (Delphi1 in IDECompatibility) then
  CheckListBox1.Checked[0] := True;
if (Delphi2 in IDECompatibility) then
  CheckListBox1.Checked[1] := True;
if (Delphi3 in IDECompatibility) then
  CheckListBox1.Checked[2] := True;
if CheckListBox1.Checked[0] then
  IDECompatibility := IDECompatibility + [Delphi1]
else
  IDECompatibility := IDECompatibility - [Delphi1];

if CheckListBox1.Checked[1] then
  IDECompatibility := IDECompatibility + [Delphi2]
else
  IDECompatibility := IDECompatibility - [Delphi2];

if CheckListBox1.Checked[2] then
  IDECompatibility := IDECompatibility + [Delphi3]
else
  IDECompatibility := IDECompatibility - [Delphi3];
更干净、简短、更好的方式:

CheckListBox1.Checked[0] := (Delphi1 in IDECompatibility);
CheckListBox1.Checked[1] := (Delphi2 in IDECompatibility);
CheckListBox1.Checked[2] := (Delphi3 in IDECompatibility);

现在我想用另一种方法来设置值。

目前我知道的唯一方法是漫长的道路:

if (Delphi1 in IDECompatibility) then
  CheckListBox1.Checked[0] := True;
if (Delphi2 in IDECompatibility) then
  CheckListBox1.Checked[1] := True;
if (Delphi3 in IDECompatibility) then
  CheckListBox1.Checked[2] := True;
if CheckListBox1.Checked[0] then
  IDECompatibility := IDECompatibility + [Delphi1]
else
  IDECompatibility := IDECompatibility - [Delphi1];

if CheckListBox1.Checked[1] then
  IDECompatibility := IDECompatibility + [Delphi2]
else
  IDECompatibility := IDECompatibility - [Delphi2];

if CheckListBox1.Checked[2] then
  IDECompatibility := IDECompatibility + [Delphi3]
else
  IDECompatibility := IDECompatibility - [Delphi3];
如果可能,我想这样做:

IDECompatibility[Delphi1] := CheckListBox1.Checked[0]; // Array type required
IDECompatibility[Delphi2] := CheckListBox1.Checked[1]; // Array type required
IDECompatibility[Delphi3] := CheckListBox1.Checked[2]; // Array type required
排除
包括
成员,但我不确定这里是否需要这些成员

那么,如上所述,有没有更简单的方法基于布尔值定义枚举类型


谢谢。

我知道您提到了XE,但是有人在看这个问题时可能会对这个更新版本的答案感兴趣

在XE6中,这可以(几乎)通过设置辅助对象来完成:

type
  TMyRange = 0..7;
  TMySet = set of TMyRange;

type
  TMySetHelper = record helper for TMySet
  public
    function GetElement(Index: TMyRange): Boolean;
    procedure SetElement(Index: TMyRange; const Value: Boolean);
    property Element[Index: TMyRange]: Boolean read GetElement write SetElement;
  end;
由于不允许将元素设为默认数组属性,因此必须指定属性名称

var
  MySet: TMySet;
begin
  MySet.Element[0] := False;
  MySet.Element[1] := not MySet.Element[0];
end;

不,目前在Delphi中没有类似数组的类型访问。我建议创建一个helper索引属性,它可以模拟类似于数组的访问,并隐藏从集合中包含或排除元素所需的代码

从我到目前为止所看到的情况来看,人们通常通过
Is
has
前缀对具有一些基本访问权限的属性添加前缀。在您的情况下,我会遵循这个规则,创建一个名为
HasIDECompatibility
的属性,或者说
IsIDECompatible
。此属性将为
布尔类型,并将具有一个getter,通过该getter可以返回元素是否位于内部集合字段中的信息。在setter中,它将根据输入值在集合中包含或排除元素

在更广义的代码中,它将是:

type
  TElement = (
    Element1,
    Element2,
    Element3
  );
  TElements = set of TElement;

  TMyClass = class
  private
    FElements: TElements;
    function GetElement(Kind: TElement): Boolean;
    procedure SetElement(Kind: TElement; Value: Boolean);
  public
    // this property is for direct access to the set field; if your class would
    // be a TComponent descendant and you'd publish this property, you'd see it
    // in the Object Inspector represented by a set of check boxes
    property Elements: TElements read FElements write FElements;
    // this property is just a helper for array like access to the internal set
    // field
    property HasElement[Kind: TElement]: Boolean read GetElement write SetElement;
  end;

implementation

{ TMyClass }

function TMyClass.GetElement(Kind: TElement): Boolean;
begin
  Result := Kind in FElements;
end;

procedure TMyClass.SetElement(Kind: TElement; Value: Boolean);
begin
  if Value then
    Include(FElements, Kind)
  else
    Exclude(FElements, Kind);
end;
以及一个示例用法:

procedure TForm1.Button1Click(Sender: TObject);
var
  MyClass: TMyClass;
begin
  MyClass := TMyClass.Create;
  try
    // write elementary property value
    MyClass.HasElement[Element1] := CheckBox1.Checked;
    MyClass.HasElement[Element2] := CheckBox2.Checked;
    // read elementary property value
    CheckBox3.Checked := MyClass.HasElement[Element1];
    CheckBox4.Checked := MyClass.HasElement[Element2];

    // or you can access MyClass.Elements set at once as you were used to do
    // which gives you two ways to include or exclude elements to the set
  finally
    MyClass.Free;
  end;
end;

基于Uwes解决方案,我创建了这个助手(需要XE6),它可以用于变量属性:

TGridOptionsHelper = record helper for TGridOptions
public
  ///  <summary>Sets a set element based on a Boolean value</summary>
  ///  <example>
  ///    with MyGrid do Options:= Options.SetOption(goEditing, False);
  ///    MyVariable.SetOption(goEditing, True);
  ///  </example>
  function SetOption(GridOption: TGridOption; const Value: Boolean): TGridOptions;
end;

function TGridOptionsHelper.SetOption(
  GridOption: TGridOption; const Value: Boolean): TGridOptions;
begin
  if Value then Include(Self, GridOption) else Exclude(Self, GridOption);
  Result:= Self;
end;
TGridOptions助手=记录TGridOptions的助手
公众的
///基于布尔值设置集合元素
///  
///使用MyGrid do Options:=Options.SetOption(goEditing,False);
///设置选项(goEditing,True);
///  
函数SetOption(GridOption:TGridOption;常量值:Boolean):TGridOptions;
结束;
函数tgridoptionHelper.SetOption(
GridOption:TGridOption;常量值:Boolean):TGridOptions;
开始
if值则包括(Self,GridOption)否则排除(Self,GridOption);
结果:=自我;
结束;

备注:与Uwes解决方案相比,我还省略了读取集合元素的代码-这应该使用
操作符中的
来完成。

您真的确定枚举是正确的选择吗?现在您已经知道,将来会有更多您今天无法命名的枚举值(XE7或XTE…)。对我来说,我会使用一个集合来表示什么是
Delphi1
Delphi2
,以及
Delphi3
?您是否试图根据最终用户正在运行的Delphi版本为其提供兼容性定制?如果是,这听起来像是一个条件编译的例子……不管他的用例如何,如果一个枚举集syntaxwise可以像一个布尔数组一样用于枚举,那就太好了。忽略
Delphi1
Delphi2
Delphi3
显示为,这只是出于示例目的。你能用一个通用列表来完成吗
TList
——或者更好,自定义
TList
;防止重复的东西,等等。这个问题中提到的集合是一个属性。记录助手是否适用于属性?我不这么认为,但目前无法验证…@TLama,至少它编译了。有趣。所以它可能会起作用。这让我想知道,如果有这样一个属性的setter,会发生什么。我希望编译器在这种情况下会失败。@TLama,我同意它首先不应该工作。与该集合属性上的普通Include或Exclude相同,该集合属性也不应该起作用。@FreeConsulting,一如既往的问题是“可以完成”和“应该完成”。我自己也很感激这是可以做到的,因为在某些情况下,它可能会派上用场。尽管如此,我还是建议少用它。这看起来很有希望,也是一个解释得很好的答案:)如果存在一个清晰的方法,它可以作为记录存在于堆栈上,不是吗?我的意思是,可以使用一个记录,而不是用一个类命中堆。但是在使用记录之前,您仍然需要使用方法清除FElements内容。@LURD,
TMyClass
是OP的初始类(来自链接的问题),我所展示的只是它的扩展(为了更好地理解这个问题而修改)。实际上,我刚才添加的是
haseElement
属性。啊,现在我明白了。我没有注意到这个联系。很抱歉