代码之家  ›  专栏  ›  技术社区  ›  Cesar Romero

如何知道var是什么类型的?

  •  8
  • Cesar Romero  · 技术社区  · 15 年前

    var
      S: string;
      Instance: IObjectType;
      Obj: TDBGrid;
      Info: PTypeInfo;
    begin
      Info:= TypeInfo(S);
      Info:= TypeInfo(Instance);
      Info:= TypeInfo(Obj);
    end
    

    此代码返回:

    [DCC Error]Unit1.pas(354):E2133 TYPEINFO标准函数需要类型标识符

    我知道非实例化变量只是一个指针地址。 在编译时,编译器解析并执行类型安全检查。

    3 回复  |  直到 15 年前
        1
  •  29
  •   Community clintgh    7 年前

    不。

    首先,没有所谓的“非实例化变量”,你只需在源文件中输入它的名字和类型就可以实例化它。

    不再存在 一旦你的程序被编译。在那之后,一切都是零碎的。

    Variant 键入。变量的类型总是 变体 ,但可以在其中存储多种类型的值。为了找出它的位置,可以使用 VarType

    任何你想用的时间 TypeInfo 若要获取与变量关联的类型的类型信息,还可以直接命名感兴趣的类型;如果变量在作用域中,则可以找到其声明并在调用 .

    如果要将任意地址传递给一个函数,并让该函数发现其自身的类型信息,那就太不走运了。你需要通过 PTypeInfo New 在指针变量上,编译器插入一个附加参数,该参数保存 要分配的类型的值。当你打电话 SetLength 类型信息 数组类型的值。

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

    这应该会导致访问冲突。 目标 两者都将读取未指定的内存地址,可能不是属于进程的地址。您请求的例程将使用变量的地址作为其输入,但仅仅使用地址是不够的。

    现在让我们仔细看看 等压 看起来像 它可能是给定类型的值,对象(实例)或类。像这样使用:

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

    你可能会反对我如何滥用这些函数,把显然是垃圾的东西传递给它们。但我想那是 只有 谈论这个话题是有意义的。如果你知道你永远不会有垃圾值,那么你无论如何都不需要你要的函数,因为你已经对你的程序有足够的了解,可以对你的变量使用真正的类型。

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

        2
  •  2
  •   Ken White    15 年前

    我不知道。可以获取类的已发布属性的RTTI(运行时类型信息),但不能获取字符串和整数等“普通”变量的RTTI。信息根本不在那里。

    此外,传递var而不传递类型的唯一方法是使用泛型TObject参数、泛型类型(D2008,如in)或非类型化参数。我想不出另一种方法来传递它,甚至可以编译它。

        3
  •  0
  •   chuacw Allen Bauer    5 年前

    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.