Reputation:
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
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
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
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