TypeInfo( type )返回有关指定类型的信息,有任何方法知道var的类型信息吗?
var
S: string;
Instance: IObjectType;
Obj: TDBGrid;
Info: PTypeInfo;
begin
Info:= TypeInfo(S);
Info:= TypeInfo(Instance);
Info:= TypeInfo(Obj);
end
此代码返回:
DCC错误单元1.PAS(354):E2133 TYPEINFO标准函数需要一个类型标识符
我知道非实例化的var只是一个指针地址。在编译时,编译器分析并执行类型安全检查。
在运行时,有没有办法了解更多关于var的信息,只传递它的地址?
发布于 2009-02-16 10:54:47
不是的。
首先,没有所谓的“非实例化变量”。您只需输入其名称并将其输入源文件即可实例化它。
第二,通过在源代码中查看变量,您已经知道了所有关于变量的知识。一旦编译程序,该变量就不再存在。在那之后,一切都只是些零碎。
指针在编译时只有一个类型。在运行时,可以对该地址执行的所有操作都已经确定。正如您已经注意到的,编译器会对此进行检查。在运行时检查变量的类型只在变量类型可能更改的语言中有用,就像在动态语言中一样。最接近德尔菲的是它的Variant
类型。变量的类型总是Variant
,但是可以在其中存储许多类型的值。要找出它所包含的内容,可以使用VarType
函数。
当您希望使用TypeInfo
获取与变量关联的类型的类型信息时,还可以直接命名您感兴趣的类型;如果变量在作用域中,则可以在调用TypeInfo
时查找其声明并使用声明的类型。
如果您想将任意地址传递给一个函数,并让该函数发现其本身的类型信息,那么您就倒霉了。相反,您需要将PTypeInfo
值作为附加参数传递。这就是所有内置的Delphi函数所做的。例如,当您对指针变量调用New
时,编译器会插入一个额外的参数,该参数保存要分配的类型的PTypeInfo
值。在动态数组上调用SetLength
时,编译器将为数组类型插入一个PTypeInfo
值。
The answer that you gave建议你寻找的不是你想要的东西。考虑到您的问题,我认为您正在寻找一个能够满足以下代码的假设函数:
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;
让我们使用IsClass
and IsObject
functions from the JCL构建这个函数:
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;
您可能会反对我将明显是垃圾的内容传递到函数中,从而滥用这些函数。但我认为这是唯一有意义的谈论这个话题。如果您知道您永远不会有垃圾值,那么您就不需要您想要的函数了,因为您已经足够了解您的程序,可以为您的变量使用真正的类型。
总之,你问错问题了。与其询问如何确定变量的类型或内存中值的类型,还应该问自己是如何进入一个不知道变量类型和数据类型的位置的。
发布于 2019-02-14 21:09:35
使用泛型,现在可以获得类型信息而不指定它。某些用户表示,以下代码不会在编译过程中没有错误。从Delphi 10西雅图版23.0.20618.2753开始,它编译时没有错误,如下面的截图所示。
program TypeInfos;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.TypInfo;
type
TTypeInfo = class
class procedure ShowTypeInfo<T>(const X: T);
end;
{ TTypeInfo }
class procedure TTypeInfo.ShowTypeInfo<T>(const X: T);
var
LTypeInfo: PTypeInfo;
begin
LTypeInfo := TypeInfo(T);
WriteLn(LTypeInfo.Name);
end;
var
L: Exception;
B: Boolean;
begin
// Console output
TTypeInfo.ShowTypeInfo(L); // Exception
TTypeInfo.ShowTypeInfo(B); // Boolean
end.
发布于 2009-02-16 10:38:55
就我所知没有。您可以获得已发布的类属性的RTTI (运行时类型信息),但对于字符串和整数等“正常”变量则不能获得RTTI。信息根本就不在那里。
此外,在不传递类型的情况下传递var的唯一方法是使用泛型TObject参数、泛型类型(如in )或非类型化参数。我想不出另一种传递它的方法,那就是编译。
https://stackoverflow.com/questions/554100
复制相似问题