user1175743
user1175743

Reputation:

Is there a easier way to define a Enum type based on a boolean value?

Overview

Not entirely sure if the question is worded appropriately or not, but I previously asked this question which relates to this one: How do I correctly implement a Set in a class as a property?

I like to keep code as short, minimal and readible as possible, and this is where I think some code could be written better but I am running into problems.


An example first of 2 ways to read the value in a Set:

The long way:

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;

The cleaner, short and better way:

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

Now I want to do it the other way, to set the values.

Currently the only way I know is the long way:

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];

If possible I would like to do something like this:

IDECompatibility[Delphi1] := CheckListBox1.Checked[0]; // Array type required
IDECompatibility[Delphi2] := CheckListBox1.Checked[1]; // Array type required
IDECompatibility[Delphi3] := CheckListBox1.Checked[2]; // Array type required

There is the Exclude and Include members but I am unsure if these are going to be needed here or not.

So, as described above - Is there a easier way to define a Enum type based on a boolean value?

Thank you.

Upvotes: 6

Views: 664

Answers (3)

maf-soft
maf-soft

Reputation: 2552

Based on Uwes solution, I created this helper (requires XE6) which can be used for variables and properties:

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;

Remark: compared to Uwes solution, I also omitted code for reading a set element - that should be done using the in operator.

Upvotes: 0

TLama
TLama

Reputation: 76693

No, there is no array like access available for set type in Delphi at this time. I would suggest making a helper indexed property which can mimic array like access and which will hide a code needed to include or exclude an element from the set.

From what I've seen so far, people usually prefix properties that has some elementary access by Is or Has prefixes. In your case I would follow this rule and make a property called HasIDECompatibility or let's say IsIDECompatible. This property will be of Boolean type and will have a getter, by which you return the information whether the element is inside the internal set field or not. In setter it will either include or exclude the element into the set depending on the input value.

In a more generalized code it would be:

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;

And an example usage:

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;

Upvotes: 5

Uwe Raabe
Uwe Raabe

Reputation: 47714

I know you mentioned XE, but someone looking at this question might be interested in this answer for a more recent version.

In XE6 this can be accomplished (almost) with a set helper:

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;

As it is not allowed to make Element the default array property, you have to specify the property name.

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

Upvotes: 5

Related Questions