如何知道var是什么类型? [英] How to know what type is a var?

查看:21
本文介绍了如何知道var是什么类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TypeInfo(Type) 返回指定类型的信息,有没有办法知道var的类型信息?

TypeInfo(Type) returns the info about the specified type, is there any way to know the typeinfo of a var?

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 只是一个指针地址.在编译时,编译器会解析并进行类型安全检查.

I know a non instantiated var is only a pointer address. At compile time, the compiler parses and do the type safety check.

在运行时,有没有什么方法可以知道更多关于var的信息,只传递它的地址?

推荐答案

没有

首先,没有非实例化变量"这样的东西.您只需键入其名称并在源文件中键入即可实例化它.

First, there's no such thing as a "non-instantiated variable." You instantiate it by the mere act of typing its name and type into your source file.

其次,通过查看源代码中的变量,您已经了解了有关变量的所有信息.一旦你的程序被编译,变量不再存在.在那之后,一切都只是点点滴滴.

Second, you already know all there is to know about a variable by looking at it in your source code. The variable ceases to exist once your program is compiled. After that, it's all just bits.

一个指针在编译时只有一个类型.在运行时,可以对该地址执行的所有操作都已确定.正如您已经指出的那样,编译器会对此进行检查.在运行时检查变量的类型仅在变量类型可能改变的语言中有用,如在动态语言中.最接近 Delphi 的是它的 Variant 类型.变量的类型总是Variant,但你可以在其中存储多种类型的值.要找出它包含的内容,您可以使用 VarType 函数.

A pointer only has a type at compile time. At run time, everything that can be done to that address has already been determined. The compiler checks for that, as you already noted. Checking the type of a variable at run time is only useful in languages where a variable's type could change, as in dynamic languages. The closest Delphi comes to that is with its Variant type. The type of the variable is always Variant, but you can store many types of values in it. To find out what it holds, you can use the VarType function.

任何时候您想使用TypeInfo 来获取与变量关联的类型的类型信息,您也可以直接命名您感兴趣的类型;如果变量在范围内,那么您可以找到它的声明并在对 TypeInfo 的调用中使用声明的类型.

Any time you could want to use TypeInfo to get the type information of the type associated with a variable, you can also directly name the type you're interested in; if the variable is in scope, then you can go find its declaration and use the declared type in your call to TypeInfo.

如果您想将任意地址传递给函数并让该函数自行发现类型信息,那您就不走运了.您需要将 PTypeInfo 值作为附加参数传递.这就是所有内置的 Delphi 函数所做的.例如,当您对指针变量调用 New 时,编译器会插入一个附加参数,该参数保存您正在分配的类型的 PTypeInfo 值.当您在动态数组上调用 SetLength 时,编译器会为数组类型插入一个 PTypeInfo 值.

If you want to pass an arbitrary address to a function and have that function discover the type information for itself, you're out of luck. You will instead need to pass the PTypeInfo value as an additional parameter. That's what all the built-in Delphi functions do. For example, when you call New on a pointer variable, the compiler inserts an additional parameter that holds the PTypeInfo value for the type you're allocating. When you call SetLength on a dynamic array, the compiler inserts a PTypeInfo value for the array type.

你给出的答案表明您正在寻找的东西不是您所要求的.鉴于您的问题,我以为您正在寻找可以满足此代码的假设函数:

The answer that you gave suggests that you're looking for something other than what you asked for. Given your question, I thought you were looking for a hypothetical function that could satisfy this code:

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 的 IsClassIsObject 函数 以构建该函数:

Let's use the IsClass and IsObject functions from the JCL to build that function:

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;

它显然不适用于上面的 SInstance,但让我们看看 Obj 会发生什么:

It obviously won't work for S or Instance above, but let's see what happens with Obj:

Info := GetVariableTypeInfo(@Obj);

这应该会导致访问冲突.Obj 没有值,所以 IsClassIsObject 都将读取一个未指定的内存地址,可能不属于您的进程.您要求使用变量地址作为其输入的例程,但仅提供地址是不够的.

That should give an access violation. Obj has no value, so IsClass and IsObject both will be reading an unspecified memory address, probably not one that belongs to your process. You asked for a routine that would use a variable's address as its input, but the mere address isn't enough.

现在让我们仔细看看 IsClassIsObject 的实际行为.这些函数接受一个任意值并检查该值是否看起来像它可能是给定类型的值,对象(实例)或类.像这样使用它:

Now let's take a closer look at how IsClass and IsObject really behave. Those functions take an arbitrary value and check whether the value looks like it might be a value of the given kind, either object (instance) or class. Use it like this:

// 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;

请注意,这些函数没有告诉您关于变量的任何信息,只告诉您它们保存的.那么,我不会真正考虑这些函数来回答如何获取有关变量的类型信息的问题.

Notice that the functions tell you nothing about the variables, only about the values they hold. I wouldn't really consider those functions, then, to answer the question of how to get type information about a variable.

此外,你说你只知道变量的地址.您找到的函数不采用变量的地址.它们取一个变量的.这是一个演示:

Furthermore, you said that all you know about the variable is its address. The functions you found do not take the address of a variable. They take the value of a variable. Here's a demonstration:

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;

您可能会反对我通过将显然是垃圾的内容传递给它们来滥用这些功能.但我认为这是讨论这个话题的唯一方式.如果你知道你永远不会有垃圾值,那么你无论如何都不需要你所要求的函数,因为你已经足够了解你的程序来为你的变量使用真正的类型.

You might object to how I'm abusing these functions by passing what's obviously garbage into them. But I think that's the only way it makes sense to talk about this topic. If you know you'll never have garbage values, then you don't need the function you're asking for anyway because you already know enough about your program to use real types for your variables.

总的来说,你问错了问题.与其问你如何确定变量的类型或内存中值的类型,你应该问你是如何让自己陷入不知道变量和数据类型的境地.

Overall, you're asking the wrong question. Instead of asking how you determine the type of a variable or the type of a value in memory, you should be asking how you got yourself into the position where you don't already know the types of your variables and your data.

这篇关于如何知道var是什么类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆