1

Delphi 不直接支持将整数类型转换为枚举的任何范围检查或超出范围的异常提升。请参阅:如何将整数转换为枚举类型? 我试图通过对枚举子范围索引的数组进行自动范围检查来解决这个问题。在我的测试程序中,我故意使用了非连续枚举,它禁用 RTTI 并为没有命名枚举但可以通过 typecasting、Inc、Dec 等访问的有效子范围值提供测试。

该程序按预期处理子范围 (2) 的非枚举元素,但不会为枚举数组生成超出范围的异常 - 但会为等效的整数索引数组生成。这有什么好的理由吗?我可以通过使用整数索引数组来解决,但枚举索引会更健壮一些。

type MyEnum = (zero,one,three=3);
var EnumCheck: array[MyEnum] of integer = (0,1,2,3);
var iEnum: integer;
var MyEnumVar: MyEnum;
var IntArray: array[0..3] of integer = (0,1,2,3);

procedure Test;
begin
{$R+}
  MyEnumVar:= MyEnum (1);         // One
  iEnum := EnumCheck[MyEnumVar];  // OK - iEnum = 1
  MyEnumVar:= MyEnum (2);         // Out-of-bound
  iEnum := EnumCheck[MyEnumVar];  // OK - iEnum = 2
  MyEnumVar:= MyEnum (3);         // Three
  iEnum := EnumCheck[MyEnumVar];  // OK - iEnum = 3
  MyEnumVar:= MyEnum (4);         // Out-of-bound
  iEnum := EnumCheck[MyEnumVar];  // no Exception; iEnum is set to random value
  iEnum := 4;
  iEnum := IntArray[iEnum];      // Exception thrown here
  iEnum := IntArray[4];          // Compiler "subrange" error
end;

使用 Delphi 10.4 更新 2

编辑:我找到了我的工作。将校验数组定义为:

var iCheck: array[Ord(Low(MyEnum))..Ord(High(MyEnum))] of integer = (0,1,2,3);

并按预期抛出超出范围的异常。

4

1 回答 1

0

我已经使用枚举记录助手将我的变通方法实现为一个相对简洁的解决方案。

type MyEnum = (Zero, One, Two, Three);

type MyEnumHelper = record helper for MyEnum
  function SetInRange(const Value: integer): boolean;
end;

function MyEnumHelper.SetInRange(const Value: integer): boolean;
var Check: array[Ord(Low(MyEnum))..Ord(High(MyEnum))] of integer;
begin
  Result := true;
  Self := MyEnum(Value);
{$UNDEF _RANGEOFF}
{$IFOPT R-} {$DEFINE _RANGEOFF} {$R+} {$ENDIF}
  try
    var iCheck := Check[Value];
  except on ERangeError do
    Exit(false);
  end;
{$IFDEF _RANGEOFF} {$R-} {$ENDIF}
end;

// Usage

function SetEnums(const Val1, Val2, Val3: integer): boolean
var MyEnumVar1, MyEnumVar2, MyEnumVar3: MyEnum;
begin
  if (not MyEnumVar1.SetInRange(Val1)) then Exit(false);
  if (not MyEnumVar2.SetInRange(Val2)) then Exit(false);
  if (not MyEnumVar3.SetInRange(Val3)) then Exit(false);
end;

注意。固定长度数组(检查)不需要手动初始化,因为我们只对范围感兴趣。

没有完全可靠的方法可以将其用于非连续枚举(正如我在原始示例中使用的那样),因为“匿名”枚举仍在范围内。而且,如果您要使用帮助程序中的实际生成值来解决此问题,那么它首先会绕过使用帮助程序的要点。

于 2022-01-27T11:30:26.830 回答