Home > Enterprise >  Converting a generic type variable to string
Converting a generic type variable to string

Time:09-17

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.

  • Related