Reputation: 27276
I have a whole lot of enum types which are coupled with a corresponding set, such as...
type
TMyEnum = (meOne, meTwo, meThree);
TMyEnums = set of TMyEnum;
I'm trying to come up with a single set of functions which can work on any enum set, rather than writing separate functions for each and every one. These functions will be responsible for interpreting the values which are included in a given set.
For a single specific set, I may have a function like this...
var
E: TMyEnum;
begin
for E := Low(TMyEnum) to High(TMyEnum) do begin
if E in SomeGivenSet then
CheckListBox.Checked[Integer(E)]:= True;
end;
end;
...and...
var
E: TMyEnum;
begin
for E := Low(TMyEnum) to High(TMyEnum) do begin
if CheckListBox.Checked[Integer(E)] then
SomeGivenSet:= SomeGivenSet + [E];
end;
end;
How do I accomplish the above to be re-usable for any given enum/set type?
Example usage:
procedure LoadEnums(AEnumType: TAnyEnumType; ASet: TAnySet; AList: TCheckListBox);
procedure SaveEnums(AEnumType: TAnyEnumType; ASet: TAnySet; AList: TCheckListBox);
LoadEnums(TMyEnum, MyEnums, lstMyEnumCheckList);
SaveEnums(TMyEnum, MyEnums, lstMyEnumCheckList);
Upvotes: 3
Views: 436
Reputation: 595896
You can try using a mix of Generics and RTTI to do what you are looking for, eg:
uses
..., CheckLst, TypInfo;
type
TEnumSerialize<EnumType: record> = class
private
class function GetEnumTypeData: PTypeData;
public
type SetType = Set of EnumType;
class procedure LoadEnums(const ASet: SetType; AList: TCheckListBox);
class procedure SaveEnums(var VSet: SetType; AList: TCheckListBox);
end;
class function TEnumSerialize<EnumType>.GetEnumTypeData: PTypeData;
var
TI: PTypeInfo;
begin
TI := TypeInfo(EnumType);
if Assigned(TI) and (TI^.Kind = tkEnumeration) then
Result := GetTypeData(TI)
else
Result := nil;
end;
class procedure TEnumSerialize<EnumType>.LoadEnums(const ASet: SetType; AList: TCheckListBox);
var
TD: PTypeData;
Value: Integer;
begin
AList.CheckAll(cbUnchecked);
TD := GetEnumTypeData;
if not Assigned(TD) then Exit;
for Value := TD^.MinValue to TD^.MaxValue do
begin
if EnumType(Value) in ASet then
AList.Checked[Value] := True;
end;
end;
class procedure TEnumSerialize<EnumType>.SaveEnums(var VSet: SetType; AList: TCheckListBox);
var
TD: PTypeData;
Value: Integer;
begin
VSet := [];
TD := GetEnumTypeData;
if not Assigned(TD) then Exit;
for Value := TD^.MinValue to TD^.MaxValue do
begin
if AList.Checked[Value] then
Include(VSet, EnumType(Value));
end;
end;
type
TMyEnum = (meOne, meTwo, meThree);
TMyEnums = set of TMyEnum;
var
MyEnums: TMyEnums;
// initialize MyEnums as needed...
TEnumSerialize<TMyEnum>.LoadEnums(MyEnums, lstMyEnumCheckList);
// use lstMyEnumCheckList as needed...
TEnumSerialize<TMyEnum>.SaveEnums(MyEnums, lstMyEnumCheckList);
// save MyEnums as needed...
Alternatively:
uses
..., CheckLst, TypInfo;
type
TEnumSerialize<SetType> = class
private
class function GetEnumTypeData: PTypeData;
public
class procedure LoadEnums(const ASet: SetType; AList: TCheckListBox);
class procedure SaveEnums(var VSet: SetType; AList: TCheckListBox);
end;
class function TEnumSerialize<SetType>.GetEnumTypeData: PTypeData;
var
TI: PTypeInfo;
begin
Result := nil;
TI := TypeInfo(SetType);
if not (Assigned(TI) and (TI^.Kind = tkSet)) then Exit;
TD := GetTypeData(TI);
if not (Assigned(TD^.CompType) and (TD^.CompType^.Kind = tkEnumeration)) then Exit;
Result := GetTypeData(TD^.CompType^);
end;
class procedure TEnumSerialize<SetType>.LoadEnums(const ASet: SetType; AList: TCheckListBox);
var
TD: PTypeData;
Value: Integer;
begin
AList.CheckAll(cbUnchecked);
TD := GetEnumTypeData;
if not Assigned(TD) then Exit;
for Value := TD^.MinValue to TD^.MaxValue do
begin
if Value in ASet then
AList.Checked[Value] := True;
end;
end;
class procedure TEnumSerialize<SetType>.SaveEnums(var VSet: SetType; AList: TCheckListBox);
var
TD: PTypeData;
Value: Integer;
begin
VSet := [];
TD := GetEnumTypeData;
if not Assigned(TD) then Exit;
for Value := TD^.MinValue to TD^.MaxValue do
begin
if AList.Checked[Value] then
Include(VSet, Value);
end;
end;
type
TMyEnum = (meOne, meTwo, meThree);
TMyEnums = set of TMyEnum;
var
MyEnums: TMyEnums;
// initialize MyEnums as needed...
TEnumSerialize<TMyEnums>.LoadEnums(MyEnums, lstMyEnumCheckList);
// use lstMyEnumCheckList as needed...
TEnumSerialize<TMyEnums>.SaveEnums(MyEnums, lstMyEnumCheckList);
// save MyEnums as needed...
If that doesn't work, you will likely have to include both enum and set types in the Generic parameters, eg:
uses
..., CheckLst, TypInfo;
type
TEnumSerialize<EnumType, SetType> = class
private
class function GetEnumTypeData: PTypeData;
public
class procedure LoadEnums(const ASet: SetType; AList: TCheckListBox);
class procedure SaveEnums(var VSet: SetType; AList: TCheckListBox);
end;
class function TEnumSerialize<EnumType, SetType>.GetEnumTypeData: PTypeData;
var
TI: PTypeInfo;
begin
Result := nil;
TI := TypeInfo(SetType);
if not (Assigned(TI) and (TI^.Kind = tkSet)) then Exit;
TD := GetTypeData(TI);
if not (Assigned(TD^.CompType) and (TD^.CompType^ = TypInfo(EnumType)) and (TD^.CompType^.Kind = tkEnumeration)) then Exit;
Result := GetTypeData(TD^.CompType^);
end;
class procedure TEnumSerialize<EnumType, SetType>.LoadEnums(const ASet: SetType; AList: TCheckListBox);
var
TD: PTypeData;
Value: Integer;
begin
AList.CheckAll(cbUnchecked);
TD := GetEnumTypeData;
if not Assigned(TD) then Exit;
for Value := TD^.MinValue to TD^.MaxValue do
begin
if EnumType(Value) in ASet then
AList.Checked[Value] := True;
end;
end;
class procedure TEnumSerialize<SetType>.SaveEnums(var VSet: SetType; AList: TCheckListBox);
var
TD: PTypeData;
Value: Integer;
begin
VSet := [];
TD := GetEnumTypeData;
if not Assigned(TD) then Exit;
for Value := TD^.MinValue to TD^.MaxValue do
begin
if AList.Checked[Value] then
Include(VSet, EnumType(Value));
end;
end;
type
TMyEnum = (meOne, meTwo, meThree);
TMyEnums = set of TMyEnum;
var
MyEnums: TMyEnums;
// initialize MyEnums as needed...
TEnumSerialize<TMyEnum, TMyEnums>.LoadEnums(MyEnums, lstMyEnumCheckList);
// use lstMyEnumCheckList as needed...
TEnumSerialize<TMyEnum, TMyEnums>.SaveEnums(MyEnums, lstMyEnumCheckList);
// save MyEnums as needed...
Upvotes: 6