【问题标题】:Converting value of type <T> into Variant, is it possible?将 <T> 类型的值转换为 Variant,可以吗?
【发布时间】:2011-10-25 15:55:25
【问题描述】:

这是一个 sn-p,显示了我想要实现的目标:

type
  TMyObject<T> = class (TObject)
    function GetVarType(Value: T): TVarType;
  end;


function TMyObject<T>.GetVarType(Value: T): TVarType;
var
  TmpValue: Variant;
begin
  TmpValue := Variant(Value); //Invalid typecast
  Result := VarType(TmpValue);
end;

我知道上面带有类型转换的方法很幼稚,但我希望你明白这一点。我想用一些转换机制来代替它。

TMyObject 将始终是简单类型,例如 Integer、String、Single、Double。

这种转换的目的是函数 VarType 为我可以存储在其他地方的每个简单类型提供整数常量。

我想知道这种转换是否可行?

感谢您的宝贵时间。

【问题讨论】:

    标签: delphi generics delphi-2009 variant


    【解决方案1】:

    使用增强的 RTTI(2010 和更新版本)在 Delphis 中可以轻松解决。太糟糕了,你仅限于 2009 年 :(

    function TMyObject<T>.GetVarType(Value: T): TVarType;
    begin
      Result := VarType(TValue.From<T>(Value).AsVariant);
    end;
    

    这仅适用于简单类型,但这是问题中指定的约束。

    【讨论】:

    • 感谢@gabr,当我切换到 D2010 时它肯定会有所帮助 :)
    【解决方案2】:

    您可以使用 RTTI 获取此信息,只需检查 TTypeInfo.Kind 属性的值:

    查看此示例代码

    {$APPTYPE CONSOLE}
    
    uses
      TypInfo,
      Variants,
      Generics.Collections,
      SysUtils;
    
    type
      TMyObject<T> = class (TObject)
        function GetVarType(Value: T): TVarType;
      end;
    
    
    function TMyObject<T>.GetVarType(Value: T): TVarType;
    begin
      Case PTypeInfo(TypeInfo(T))^.Kind of
        tkInteger : Result:=varInteger;
        tkFloat   : Result:=varDouble;
        tkString  : Result:=varString;
        tkUString : Result:=varUString;
        //add more types here
      End;
    end;
    
    Var
      LObj : TMyObject<Integer>;
    begin
      try
         Writeln(VarTypeAsText(TMyObject<Integer>.Create.GetVarType(5)));
         Writeln(VarTypeAsText(TMyObject<String>.Create.GetVarType('Test')));
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
      Readln;
    end.
    

    这将返回

    Integer
    UnicodeString
    

    【讨论】:

      【解决方案3】:

      我看不出用泛型怎么可能做到这一点。编译器需要知道T 类型的实例可以分配给任何可能的T 的Variant。您无法告诉编译器这是可能的。

      如果这是 C++ 中的模板,那么这将是微不足道的。

      【讨论】:

      • @seth 我不知道你是德尔福用户。我总是把你当作花括号的家伙!
      • 通常但并非唯一。我使用 Delphi 作为 C# 的本机可执行生成版本(不能忍受不能使用在线汇编)并且非常喜欢它。
      【解决方案4】:

      感谢大家的回答:

      正如@RRUZ 所表明的那样(我的意思不是严格分配,而是提取数据类型)。我在等待任何答案的同时独自工作,并找到了更通用的解决方案。

      所以我把它放在这里:

      type
        TMyObject<T> = class (TObject)
          function GetVarType(Value: T): TVarType;
        end;
      
      
      function TMyObject<T>.GetVarType(Value: T): TVarType;
      begin
        Result := GetTypeData(TypeInfo(T)).varType;
      end;
      

      再次感谢!

      【讨论】:

      • 当TypeInfo(T).Kind 不是tkDynArray 时,是否有任何迹象表明varType 包含有效值?或者存储在varType 中的整数实际上是TVarType 值,因为动态数组可以保存Variant 不能保存的东西?我认为两者都不一定是真的。
      • @RobKennedy 恐怕你是对的。我不明白为什么它没有按预期工作。真可惜……
      • 它没有按预期工作因为我之前指出的问题。您正在读取的值不包含您想要的数据类型,并不总是有效的,甚至不代表您最初认为它所做的事情。 (它表示动态数组的元素类型,而不是T本身的类型,它应该是varType的数组。)
      • @Rob 我不明白,如果我以这种方式创建 TMyObject: MyObject := TMyObject.Create 并且我将一个整数传递给 GetVarType 函数,那么为什么 T 是不代表整数而是动态数组的某个元素?
      • 我没有说 T 是动态数组的元素。 TTypeInfo 表示某种类型的类型信息。 当该类型是动态数组时,TTypeInfo.varType 字段有效并保存数组的元素类型。例如,如果 T 是 array of Char,则 varType still 不会给你想要的答案。而不是一个表示“Char 数组”的整数,你会得到一个表示“Char”的整数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      • 1970-01-01
      • 1970-01-01
      • 2019-09-06
      • 2016-05-07
      相关资源
      最近更新 更多