不。
首先,没有“非实例化变量”之类的东西。您只需键入其名称并将其键入源文件即可实例化它。
其次,通过在源代码中查看变量,您已经了解了有关变量的所有信息。编译程序后,该变量将不复存在。在那之后,一切都只是一点点。
指针仅在编译时具有类型。在运行时,可以对该地址执行的所有操作都已确定。正如您已经指出的那样,编译器会对此进行检查。在运行时检查变量的类型仅在变量类型可能改变的语言中有用,例如在动态语言中。最接近德尔福的是它的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
andIsObject
函数来构建该函数:
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;
您可能会反对我通过将明显是垃圾的东西传递给它们来滥用这些功能。但我认为这是谈论这个话题的唯一方式。如果你知道你永远不会有垃圾值,那么你无论如何都不需要你要求的函数,因为你已经对你的程序有足够的了解,可以为你的变量使用真正的类型。
总的来说,你问错了问题。与其问你如何确定变量的类型或内存中的值的类型,不如问你是如何使自己处于不知道变量和数据类型的位置的。