TypeInfo(Type)返回有关指定类型的信息,有没有办法知道var的typeinfo?
var S: string; Instance: IObjectType; Obj: TDBGrid; Info: PTypeInfo; begin Info:= TypeInfo(S); Info:= TypeInfo(Instance); Info:= TypeInfo(Obj); end
此代码返回:
[DCC错误] Unit1.pas(354):E2133 TYPEINFO标准函数需要类型标识符
我知道非实例化的var只是一个指针地址.在编译时,编译器解析并执行类型安全检查.
在运行时,有没有办法知道更多关于var,只传递其地址?
没有.
首先,没有"非实例变量"这样的东西.只需在源文件中键入其名称和类型即可实例化它.
其次,通过在源代码中查看变量,您已经知道所有关于变量的知识.编译程序后,变量不再存在.在那之后,它只是位.
指针在编译时只有一个类型.在运行时,已经确定了可以对该地址执行的所有操作.正如您已经指出的那样,编译器会检查它.在运行时检查变量的类型仅在变量类型可能更改的语言中有用,如在动态语言中.最接近Delphi的是它的Variant
类型.变量的类型始终是Variant
,但您可以在其中存储许多类型的值.要了解它的含义,您可以使用该VarType
功能.
每当您想要使用TypeInfo
获取与变量关联的类型的类型信息时,您也可以直接命名您感兴趣的类型; 如果变量在范围内,那么你可以找到它的声明并在你的调用中使用声明的类型TypeInfo
.
如果你想将一个任意地址传递给一个函数并让该函数发现它自己的类型信息,那你就不走运了.您将需要将PTypeInfo
值作为附加参数传递.这就是所有内置Delphi函数的功能.例如,当您调用New
指针变量时,编译器会插入一个附加参数,该参数保存PTypeInfo
您要分配的类型的值.调用SetLength
动态数组时,编译器会PTypeInfo
为数组类型插入一个值.
您给出的答案表明您正在寻找除您要求之外的其他内容.鉴于您的问题,我认为您正在寻找一个可以满足此代码的假设函数:
var S: string; Instance: IObjectType; Obj: TDBGrid; Info: PTypeInfo; begin Info:= GetVariableTypeInfo(@S); Assert(Info = TypeInfo(string)); Info:= GetVariableTypeInfo(@Instance); Assert(Info = TypeInfo(IObjectType)); Info:= GetVariableTypeInfo(@Obj); Assert(Info = TypeInfo(TDBGrid)); end;
让我们使用JCL中的IsClass
和IsObject
函数来构建该函数:
function GetVariableTypeInfo(pvar: Pointer): PTypeInfo; begin if not Assigned(pvar) then Result := nil else if IsClass(PPointer(pvar)^) then Result := PClass(pvar).ClassInfo else if IsObject(PPointer(pvar)^) then Result := PObject(pvar).ClassInfo else raise EUnknownResult.Create; end;
它显然不适用于S
或Instance
超过,但让我们看看会发生什么Obj
:
Info := GetVariableTypeInfo(@Obj);
这应该会导致访问冲突.Obj
没有价值,所以IsClass
与IsObject
两者都将被读取未指定的内存地址,可能不是一个属于你的进程.您要求使用变量的地址作为输入的例程,但仅仅是地址是不够的.
现在让我们仔细看看如何IsClass
以及IsObject
真正的行为.这些函数采用任意值并检查值是否看起来可能是给定类型的值,无论是对象(实例)还是类.像这样使用它:
// This code will yield no assertion failures. var p: Pointer; o: TObject; a: array of Integer; begin p := TDBGrid; Assert(IsClass(p)); p := TForm.Create(nil); Assert(IsObject(p)); // So far, so good. Works just as expected. // Now things get interesting: Pointer(a) := p; Assert(IsObject(a)); Pointer(a) := nil; // A dynamic array is an object? Hmm. o := nil; try IsObject(o); Assert(False); except on e: TObject do Assert(e is EAccessViolation); end; // The variable is clearly a TObject, but since it // doesn't hold a reference to an object, IsObject // can't check whether its class field looks like // a valid class reference. end;
请注意,这些函数不会告诉您有关变量的任何信息,只会告诉它们所持有的值.那么,我不会真正考虑这些函数来回答如何获取有关变量的类型信息的问题.
此外,你说你对变量的所有了解都是它的地址.您找到的函数不会获取变量的地址.它们取一个变量的值.这是一个演示:
var c: TClass; begin c := TDBGrid; Assert(IsClass(c)); Assert(not IsClass(@c)); // Address of variable Assert(IsObject(@c)); // Address of variable is an object? end;
你可能会反对我如何通过将明显的垃圾传递给他们来滥用这些功能.但我认为这是谈论这个话题的唯一方法.如果你知道你永远不会有垃圾值,那么你不需要你要求的功能,因为你已经对你的程序有足够的了解,可以使用真实的变量类型.
总的来说,你问的是错误的问题.您应该问自己如何进入不了解变量类型和数据的位置,而不是询问如何确定变量的类型或内存中值的类型.