将类型为<T>的值转换为Variant,是否可能?

6
这是一个片段,展示了我想要实现的目标:

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为每种简单类型给出整数常量,我可以将其存储在其他地方。

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

感谢您的时间。

4个回答

7

使用增强型 RTTI (2010 或更高版本)可以轻松在 Delphi 中解决这个问题。遗憾的是,您只能使用2009版本,无法使用该功能。

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

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

谢谢@gabr,当我转换到D2010时,这肯定会很有帮助 :) - Wodzu

6
你可以使用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

1

感谢大家的回答:

正如@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不能保存的内容?我认为两者都不一定是真实的。 - Rob Kennedy
@RobKennedy,恐怕你是对的。我不明白为什么它不能按预期工作。真遗憾... - Wodzu
由于我之前指出的问题,它并未按预期工作。你所读取的值不包含你想要的数据类型,它也不总是有效,并且甚至不能真实地表示你最初认为的那样。它代表的是动态数组的"元素类型",而不是T本身的类型,后者将是"varType的数组"。 - Rob Kennedy
@Rob 我不明白,如果我用这种方式创建TMyObject<T>:MyObject := TMyObject<Integer>.Create,并将整数传递给GetVarType函数,那么为什么T不代表整数而是动态数组的某个元素? - Wodzu
我并没有说T是动态数组的一个元素。TTypeInfo代表某种类型的类型信息。当该类型是动态数组时,TTypeInfo.varType字段是有效的,并保存了数组的元素类型。例如,如果T是array of Char,varType仍然不能给出您想要的答案。您将得到一个整数,表示“Char”,而不是表示“array of Char”的整数。 - Rob Kennedy

1

我不知道如何使用泛型来实现这个。编译器需要知道类型 T 的实例可以被赋值给任何可能的 TVariant。你无法告诉编译器这是可能的。

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


@seth,我不知道你是Delphi用户。我一直认为你是花括号的那种人! - David Heffernan
1
通常而不是专属地,我使用Delphi作为生成本地可执行文件的C#版本(无法使用在线汇编感到难受),并且我非常喜欢它。 - Seth Carnegie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接