我有一个程序,其中很多结构被定义为char和记录的静态数组(通常由char数组组成,但这并不重要)。
我正在尝试为这些结构创建一个通用接口,因此可以将它们传递给后端C DLL。
我能够使用<T: record>
约束来处理所有类型的记录,但array[0..n] of char
违反了“非可空值类型”规则。
我可以通过为不同的静态数组声明类型来使用无约束泛型(TMyArray = array[0..5] of char
- 这很好,因为它已经存在于现有代码中),但我需要丢失<T: record>
约束。由于我的代码不适用于类或动态数组,我希望能够将T
限制为记录或静态数组char。
我能够有两个带有和不带record
约束的构造函数。然后我可以通过使用旧式RTTI来测试无约束类型是一个数组:
var
l: PTypeInfo;
begin
l := TypeInfo(T);
assert(l.Kind = tkArray);
end;
但我不认为我可以检查包含的类型是否为char? 2010 RTTI抱怨T必须是一个班级,所以我认为这也不是一个好的。 我可以通过创建仅包含我的静态字符数组的记录来解决它,但这感觉有点软糖并且在代码中看起来很笨拙。
答案 0 :(得分:3)
这是一个编译器缺陷。固定长度数组是不可为空的值类型。这个缺陷仍然存在于Delphi 10 Seattle中。该程序无法编译:
{$APPTYPE CONSOLE}
type
TFoo = record
class procedure Bar<T: record>(const arg: T); static;
end;
class procedure TFoo.Bar<T>(const arg: T);
begin
end;
type
TArr = array [0..0] of char;
var
Arr: TArr;
begin
TFoo.Bar<TArr>(Arr);
end.
错误是:
[dcc32错误] E2512类型参数&#39; T&#39;必须是不可为空的值类型
所以,我猜你必须使用RTTI进行运行时检查。你当然可以做到。该计划表明:
{$APPTYPE CONSOLE}
uses
Rtti, TypInfo;
type
TFoo = record
class procedure Bar<T>(const arg: T); static;
end;
class procedure TFoo.Bar<T>(const arg: T);
var
TypInfo: PTypeInfo;
ArrayTypeData: TArrayTypeData;
begin
TypInfo := TypeInfo(T);
if TypInfo.Kind = tkArray then begin
ArrayTypeData := GetTypeData(TypInfo).ArrayData;
Writeln(ord(ArrayTypeData.ElType^.Kind));
Writeln(ArrayTypeData.Size);
Writeln(ArrayTypeData.ElCount);
Writeln(ArrayTypeData.DimCount);
end;
end;
type
TArr = array [1..32] of char;
var
Arr: TArr;
begin
TFoo.Bar<TArr>(Arr);
Readln;
end.
输出结果为:
9 64 32 1
请注意ord(tkWChar) == 9
。因此,这为您提供了执行以下操作的方法:
您需要检查类型是否符合要求的所有信息。