I'm trying to convert a generic variable of type T
into string
.
TMyTest = class
class function GetAsString<T>(const AValue : T) : string; static;
end;
...
uses
System.Rtti;
class function TMyTest.GetAsString<T>(const AValue : T) : string;
begin
Result := TValue.From<T>(AValue).ToString();
end;
It works good using several types (like Integer
, Double
, Boolean
...) but it "fails" using Variant
variables.
procedure TForm1.FormCreate(Sender: TObject);
var
Tmp : Variant;
begin
Tmp := 123;
ShowMessage(TMyTest.GetAsString<Variant>(Tmp));
end;
It produces the following output:
(variant)
I was expecting the same output obtained by the VarToStr
function (But I cannot use that function with generic variables):
123
CodePudding user response:
You can check whether T
is variant and then use VarToStr
on AsVariant
function.
You can easily extend that function to cater for other types where ToString
will not give you expected result.
uses
System.TypInfo, System.Rtti;
class function TMyTest.GetAsString<T>(const AValue : T) : string;
begin
if PTypeInfo(TypeInfo(T)).Kind = tkVariant then
Result := VarToStr(TValue.From<T>(AValue).AsVariant)
else
Result := TValue.From<T>(AValue).ToString();
end;
CodePudding user response:
You can check the type of T
using RTTI, and then call VarToStr()
when T
is a Variant
, eg:
class function TMyTest.GetAsString<T>(const AValue : T) : string;
begin
if TypeInfo(T) = TypeInfo(Variant) then begin
// yes, the following cast looks odd, but the compiler can't validate
// T is really a Variant in this context, as it syntax-checks the code
// *before* instantiating the Generic, so a runtime cast is needed.
// The TypeInfo check above will ensure the cast is safe...
Result := VarToStr({AValue}PVariant(@AValue)^);
end else begin
Result := TValue.From<T>(AValue).ToString;
end;
end;
Or, in XE7 , you can use the GetTypeKind()
intrinsic instead:
class function TMyTest.GetAsString<T>(const AValue : T) : string;
begin
if GetTypeKind(T) = tkVariant then begin
Result := VarToStr({AValue}PVariant(@AValue)^);
end else begin
Result := TValue.From<T>(AValue).ToString;
end;
end;
Either approach will allow the compiler to optimize the code by dropping the unused branch from the executable, as both comparisons are treated as compile-time constants.
Note: other TTypeKind
values types that TValue.ToString
does not support are tkUnknown
, tkArray
, tkRecord
, and tkDynArray
.