Ces*_*ero 10 delphi runtime typeinfo
TypeInfo(Type)返回有关指定类型的信息,有没有办法知道var的typeinfo?
var
S: string;
Instance: IObjectType;
Obj: TDBGrid;
Info: PTypeInfo;
begin
Info:= TypeInfo(S);
Info:= TypeInfo(Instance);
Info:= TypeInfo(Obj);
end
Run Code Online (Sandbox Code Playgroud)
此代码返回:
[DCC错误] Unit1.pas(354):E2133 TYPEINFO标准函数需要类型标识符
我知道非实例化的var只是一个指针地址.在编译时,编译器解析并执行类型安全检查.
在运行时,有没有办法知道更多关于var,只传递其地址?
Rob*_*edy 29
没有.
首先,没有"非实例变量"这样的东西.只需在源文件中键入其名称和类型即可实例化它.
其次,通过在源代码中查看变量,您已经知道所有关于变量的知识.编译程序后,变量不再存在.在那之后,它只是位.
指针在编译时只有一个类型.在运行时,已经确定了可以对该地址执行的所有操作.正如您已经指出的那样,编译器会检查它.在运行时检查变量的类型仅在变量类型可能更改的语言中有用,如在动态语言中.最接近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;
Run Code Online (Sandbox Code Playgroud)
让我们使用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;
Run Code Online (Sandbox Code Playgroud)
它显然不适用于S或Instance超过,但让我们看看会发生什么Obj:
Info := GetVariableTypeInfo(@Obj);
Run Code Online (Sandbox Code Playgroud)
这应该会导致访问冲突.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;
Run Code Online (Sandbox Code Playgroud)
请注意,这些函数不会告诉您有关变量的任何信息,只会告诉它们所持有的值.那么,我不会真正考虑这些函数来回答如何获取有关变量的类型信息的问题.
此外,你说你对变量的所有了解都是它的地址.您找到的函数不会获取变量的地址.它们取一个变量的值.这是一个演示:
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;
Run Code Online (Sandbox Code Playgroud)
你可能会反对我如何通过将明显的垃圾传递给他们来滥用这些功能.但我认为这是谈论这个话题的唯一方法.如果你知道你永远不会有垃圾值,那么你不需要你要求的功能,因为你已经对你的程序有足够的了解,可以使用真实的变量类型.
总的来说,你问的是错误的问题.您应该问自己如何进入不了解变量类型和数据的位置,而不是询问如何确定变量的类型或内存中值的类型.
从来没听说过。您可以获取类的已发布属性的 RTTI(运行时类型信息),但不能获取字符串和整数等“普通”变量。这些信息根本不存在。
此外,在不传递类型的情况下传递 var 的唯一方法是使用泛型 TObject 参数、泛型类型(D2008,如 中)或作为无类型参数。我想不出另一种可以编译的传递它的方法。