什么德尔福类型为'整数'?

时间:2016-04-22 10:02:45

标签: delphi types

我有几个这样的硬编码验证:

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上)

4 个答案:

答案 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;