我有几个这样的硬编码验证:
const
cLstAct = 1;
cLstOrg = 4;
cLstClockAct = 11;
const
FUNCT_1 = 224;
FUNCT_2 = 127;
FUNCT_3 = 3;
if lFuncID in [FUNCT_1,FUNCT_2,FUNCT_3] then ...
if not (lListType in [cLstAct..cLstOrg,cLstClockAct]) then ...
if not (lPurpose in [0..2]) then ...
我想用像
这样的常用方法替换function ValidateInSet(AIntValue: integer; AIntSet: @@@): Boolean;
begin
Result := (AIntValue in AIntSet);
if not Result then ...
end;
但是为AIntSet
选择哪种类型?
目前在整个代码中要测试的值达到const值232(所以我可以使用例如TByteSet = Set of Byte),但是我可以预见到当我们进入E1012 Constant expression violates subrange bounds
时常数值超过255。
我的Google-fu在这里让我失望......
(目前在Delphi Seattle Update 1上)
答案 0 :(得分:8)
使用字典AddOrSetValue
。价值无关紧要,你只关心钥匙。如果字典包含特定键,则该键是该组的成员。使用Remove
添加成员,ContainsKey
删除成员,使用EXTRACT()
来测试成员资格。
使用字典的关键是它为您提供O(1)查找。
您不希望将此类型直接用作套装。你应该将它包装在一个只暴露set like功能的类中。可以在此处找到一个示例:https://stackoverflow.com/a/33530037/505088
答案 1 :(得分:4)
您可以使用array of Integer
:
function ValidateInSet(AIntValue: integer; AIntSet: array of Integer): Boolean;
var
I: Integer;
begin
Result := False;
for I := Low(AIntSet) to High(AIntSet) do
begin
if AIntSet[I] = AIntValue then
begin
Result := True;
Break;
end;
end;
if not Result then ...
end;
const
cLstAct = 1;
cLstOrg = 4;
cLstClockAct = 11;
const
FUNCT_1 = 224;
FUNCT_2 = 127;
FUNCT_3 = 3;
if ValidateInSet(lFuncID, [FUNCT_1, FUNCT_2, FUNCT_3]) then ...
if not ValidateInSet(lListType, [cLstAct, 2, 3, cLstOrg, cLstClockAct]) then ...
if not ValidateInSet(lPurpose, [0, 1, 2]) then ...
答案 2 :(得分:1)
如果您使用的是最近的Delphi版本,则可以使用TArray<Integer>
。
function ValidateInSet(AIntValue: integer; const AIntSet: TArray<Integer>): Boolean;
var
N: Integer;
begin
{ option1 : if AIntSet is always sorted }
result := TArray.BinarySearch(AIntSet, AIntValue, N);
{ option 2: works for any array }
result := false;
for N in AIntSet do begin
if AIntValue = N then begin
result := true;
Break;
end;
end;
if not Result then begin
// ...
end;
end;
调用仅与集合相同(范围除外):
if ValidateInSet(lFuncID, [FUNCT_1,FUNCT_2,FUNCT_3]) then begin
end;
答案 3 :(得分:1)
直接答案是TBits
class
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.Classes.TBits.Bits
注意:这只能从Delphi XE4开始使用 - http://qc.embarcadero.com/wc/qcmain.aspx?d=108829
但是对于你的&#34;整数组&#34;在大多数虚增的情况下,它会占用2^31 / 8
字节的内存(因为甚至不会考虑整数的负值),这将是很多...
所以我希望你永远不会真的想要一整套整数。或者你应该投资稀疏阵列。
function ValidateInSet(const AIntValue: integer; const AIntSet: TBits): Boolean;
begin
Result := (AIntValue >= 0) and (AIntValue < AIntSet.Size);
if Result then
Result := AIntSet.Bits[AIntValue];
if not Result then ...
v-a-l-i-d-a-t-e
end;
或者更确切地说
function ValidateInSet(const AIntValue: integer; const AIntSet: TBits): Boolean;
begin
Result := false;
if AIntValue < 0 then exit; // Validation criterion #1
if AIntValue >= AIntSet.Size then exit; // Validation criterion #2
if not AIntSet.Bits[AIntValue] then exit; // Validation criterion #3
if .... then exit; // Validation criterion #4
if .... then exit; // Validation criterion #5
if .... then exit; // Validation criterion #6
Result := true;
end;
或者
TSetTestCriterion = TFunc<Integer, Boolean>;
TSetTestCriteria = TArray<TFunc<Integer, Boolean>>;
function ValidateInSet(const AIntValue: integer;
const AIntSet: TBits; const Tests: TSetTestCriteria = nil): Boolean;
var ExtraTest: TSetTestCriterion;
begin
Result := false;
if AIntValue < 0 then exit; // Validation criterion #1
if AIntValue >= AIntSet.Size then exit; // Validation criterion #2
if not AIntSet.Bits[AIntValue] then exit; // Validation criterion #3
if Tests <> nil then // Validation criteria #4, #5, #6, ...
for ExtraTest in Tests do
if not ExtraTest(AIntValue) then exit;
Result := true;
end;
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.SysUtils.TFunc
现在 - 只是为了演示,在真实的应用程序中,您将创建这些集合和数组一次并缓存很长时间(永远,或者至少除非配置更改需要重建它们)。
Type FuncIDs = ( FUNCT_3 = 3, FUNCT_2 = 127, FUNCT_1 = 224);
var MysticGlobalFlag: Boolean;
function ValidateFuncID( const lFuncID: FuncIDs): Boolean;
var map: TBits;
begin
map := TBits.Create;
try
map.Size := High(lFuncID) + 1;
map.Bits[ Ord(Func_1) ] := True;
map.Bits[ Ord(Func_2) ] := True;
map.Bits[ Ord(Func_3) ] := True;
Result := ValidateInSet( Ord(lFuncID), map,
TSetTestCriteria.Create(
function( lFuncID: integer) : Boolean
begin
Result := MysticGlobalFlag or (lFuncID <> Ord(FuncIDs.FUNC_2))
end
,
function( lFuncID: integer) : Boolean
begin
Result := (lFuncID <> Ord(FuncIDs.FUNC_3)) or (DayOfTheWeek(Now()) = 4)
end
)
);
finally
map.Destroy;
end;
if not Result then // from the original question code
... // seems like a placeholder for error handling or object creation and registration
end;