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;
Res开发者_开发技巧ult := T(PTemp^);
end;
Usage:
type
TEnumTest = (etFirst, etSecond);
var
D: TEnumTest;
begin
D := TEnumUtils.GetAs<TEnumTest>('etFirst');
end;
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.
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;
What you're not seeing is the way TValue was designed. It's intended specifically as a way to contain values, not a way to convert them. If you want to convert between srtings and enums, as you said, you already know how. Use the functions provided for that purpose in TypeInfo.
So you know how to do this:
function StrToEnumTest(aStr:String):TEnumTest;
begin
result := TEnumTest(GetEnumValue(TypeInfo(TEnumTest),aStr));
end;
But you don't want to do it that way? Why? I wish we could do this:
inline function StrToEnumTest(aStr:String):<T>;
begin
result := <T>(GetEnumValue(TypeInfo(<T>),aStr));
end;
精彩评论