Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting an string to a enum type using TValue?

I want to convert an string to an enum type using TValue, I googled but I didn't find how to do that.

type 
  TEnumTest = (etFirst, etSecond);

var 
  D: TEnumTest;
begin
  D := StrToENumTest('etFirst');
end;

function StrToEnumTest(pStr:String):TEnumTest;
var 
  V: TValue;
begin
  V := TValue.From<String>(pstr);
  Result := V.AsType<TEnumTest>;
end;

It doesn't work. That's must be something stupid I'm not seeing - but I didn't found it. What I made wrong?

I know how to use GetEnumValue.

EDIT: @Warren, it goes here as this is easier to post code:

  TEnumUtils = class
    class function GetAs<T>(pValor: String): T;
  end;

class function TEnumUtils.GetAs<T>(pValor: String): T;
var
  Tipo: PTypeInfo;
  Temp: Integer;
  PTemp: Pointer;

begin
   Tipo := TypeInfo(T);
   Temp := GetEnumValue(Tipo, pValor);
   PTemp := @Temp;
   Result := T(PTemp^);
end;

Usage:

type 
  TEnumTest = (etFirst, etSecond);

var 
  D: TEnumTest;
begin
  D := TEnumUtils.GetAs<TEnumTest>('etFirst');
end;  
like image 825
Fabricio Araujo Avatar asked Mar 18 '10 18:03

Fabricio Araujo


2 Answers

is this what you was looking for?

Using Generics & RTTI to get enum string name or enum value

Enum conversion with Generics / RTTI Unit System.RTTI is cross platform and contains a great class for converting enum to string and back: TRttiEnumerationType

The TRttiEnumerationType class has two class functions (methods you can call without creating an instance of the class) that clean up the code required from using the TypInfo methods. The easy reading version of these method declarations is:

class function GetName(AValue: T):string; class function GetValue(AName: string): T; Note these methods use Generics (thats the T bit). Generics are very cool as they allow you to write functionality once and then reuse it with different types at different times in code.

In this instance TRttiEnumerationType’s generic methods are for use with Enums only and not other class types as the functionality defined is specific for Enum’s.

To convert the TCompass enum now after adding RTTI to the uses would look like this.

S := TRttiEnumerationType.GetName(D); ShowMessage(S); To convert back from a string is also simpler.

D := TRttiEnumerationType.GetValue(S); How much easier is that to read! and as we have only had to declare the type once, we have less chance of silly copy paste errors in code.

like image 178
Bahaa Avatar answered Oct 18 '22 01:10

Bahaa


You can use the same approach as it's write in the top of this page with GetEnumValue. You can easy declare a codeblock like this:

unit Unit3;

interface

uses
   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
   System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, 
   typinfo, Vcl.StdCtrls;

   Type TMyEnumerator=(enm_Case0, enm_Case1, enm_Case2);

   Type TEnumConverter = class
   public
        class function EnumToInt<T>(const enValue: T): Integer;
        class function EnumToString<T>(enValue: T): string;
        class procedure StringToEnum<T>(strValue:String; var enValue:T);
   end;

implementation

class function TEnumConverter.EnumToInt<T>(const enValue: T): Integer;
begin
   Result := 0;
   Move(enValue, Result, sizeOf(enValue));
end;

class function TEnumConverter.EnumToString<T>(enValue: T): string;
begin
  Result := GetEnumName(TypeInfo(T), EnumToInt(enValue));
end;

 class procedure TEnumConverter.StringToEnum<T>(strValue: String; var enValue:T);
   var Tipo : PTypeInfo;
       Temp:Integer;
       PTemp : pointer;
begin
    Tipo := TypeInfo(T);
    Temp := GetEnumValue(Tipo, strValue);
    PTemp := @Temp;
    enValue := T(PTemp^);
end;

procedure TForm3.Button1Click(Sender: TObject);
   var s: String;
       v : TMyEnumerator;
begin
       { ************** Example *************** }

       showmessage(TEnumConverter.EnumToString(enm_Case1)); 

        s := 'enm_Case2';
        TEnumConverter.StringToEnum(s, v);

   case v of
     enm_Case0: showmessage('ok -> enm_Case0');
     enm_Case1: showmessage('ok -> enm_Case1');
     enm_Case2: showmessage('ok -> enm_Case2');
   end;

end;
like image 40
F. Fabiano Avatar answered Oct 18 '22 01:10

F. Fabiano