如何遍历任何给定集合中的枚举?

Jer*_*dge 4 delphi enums set

我有很多枚举类型,它们与相应的集合相结合,例如...

type
  TMyEnum = (meOne, meTwo, meThree);
  TMyEnums = set of TMyEnum;
Run Code Online (Sandbox Code Playgroud)

我试图提出一组可以在任何枚举集上工作的函数,而不是为每个函数编写单独的函数。这些函数将负责解释给定集合中包含的值。

对于单个特定的集合,我可能有这样的功能......

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;
Run Code Online (Sandbox Code Playgroud)

...和...

var
  E: TMyEnum;
begin
  for E := Low(TMyEnum) to High(TMyEnum) do begin
    if CheckListBox.Checked[Integer(E)] then
      SomeGivenSet:= SomeGivenSet + [E];
  end;
end;
Run Code Online (Sandbox Code Playgroud)

我如何完成上述操作以对任何给定的枚举/集合类型进行重用?

用法示例:

procedure LoadEnums(AEnumType: TAnyEnumType; ASet: TAnySet; AList: TCheckListBox);
procedure SaveEnums(AEnumType: TAnyEnumType; ASet: TAnySet; AList: TCheckListBox);

LoadEnums(TMyEnum, MyEnums, lstMyEnumCheckList);
SaveEnums(TMyEnum, MyEnums, lstMyEnumCheckList);
Run Code Online (Sandbox Code Playgroud)

Rem*_*eau 5

您可以尝试混合使用泛型和 RTTI 来执行您要查找的操作,例如:

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;
Run Code Online (Sandbox Code Playgroud)
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...
Run Code Online (Sandbox Code Playgroud)

或者:

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;
Run Code Online (Sandbox Code Playgroud)
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...
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,您可能必须在 Generic 参数中同时包含 enum 和 set 类型,例如:

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;
Run Code Online (Sandbox Code Playgroud)
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...
Run Code Online (Sandbox Code Playgroud)