Como atravessar os enums em qualquer conjunto?
Eu tenho muitos tipos de enum que são acoplados a um conjunto correspondente, como ...
type
TMyEnum = (meOne, meTwo, meThree);
TMyEnums = set of TMyEnum;
Estou tentando criar um único conjunto de funções que possa funcionar em qualquer conjunto de enum, em vez de escrever funções separadas para cada um. Essas funções serão responsáveis por interpretar os valores que estão incluídos em um determinado conjunto.
Para um único conjunto específico, posso ter uma função como esta ...
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;
...e...
var
E: TMyEnum;
begin
for E := Low(TMyEnum) to High(TMyEnum) do begin
if CheckListBox.Checked[Integer(E)] then
SomeGivenSet:= SomeGivenSet + [E];
end;
end;
Como faço para que o acima seja reutilizável para qualquer tipo de enum / set?
Exemplo de uso:
procedure LoadEnums(AEnumType: TAnyEnumType; ASet: TAnySet; AList: TCheckListBox);
procedure SaveEnums(AEnumType: TAnyEnumType; ASet: TAnySet; AList: TCheckListBox);
LoadEnums(TMyEnum, MyEnums, lstMyEnumCheckList);
SaveEnums(TMyEnum, MyEnums, lstMyEnumCheckList);
Respostas
Você pode tentar usar uma mistura de genéricos e RTTI para fazer o que está procurando, por exemplo:
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...
Alternativamente:
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...
Se isso não funcionar, você provavelmente terá que incluir os tipos enum e set nos parâmetros genéricos, por exemplo:
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...