我有很多枚举类型,它们与相应的集合相结合,例如...
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)
您可以尝试混合使用泛型和 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)