Преобразование строки в тип enum с использованием TValue?
Я хочу преобразовать строку в тип enum с помощью TValue, я погуглил, но не нашел, как это сделать.
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;
Не работает Это должно быть что-то глупое, я не вижу - но я не нашел это. Что я сделал не так?
Я знаю, как использовать GetEnumValue.
РЕДАКТИРОВАТЬ: @Warren, это идет здесь, так как это легче разместить код:
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;
Использование:
type
TEnumTest = (etFirst, etSecond);
var
D: TEnumTest;
begin
D := TEnumUtils.GetAs<TEnumTest>('etFirst');
end;
4 ответа
То, что вы не видите, это то, как TValue был разработан. Он предназначен специально для хранения значений, а не для их преобразования. Если вы хотите конвертировать srtings и enums, как вы сказали, вы уже знаете, как это сделать. Используйте функции, предусмотренные для этой цели в TypeInfo.
Это то, что вы искали?
Использование Generics & RTTI для получения имени строки enum или значения enum
Преобразование enum с помощью Generics / RTTI Unit System.RTTI является кроссплатформенным и содержит отличный класс для преобразования enum в строку и обратно: TRttiEnumerationType
Класс TRttiEnumerationType имеет две функции класса (методы, которые вы можете вызывать без создания экземпляра класса), которые очищают код, необходимый для использования методов TypInfo. Легко читаемая версия этих объявлений методов:
функция класса GetName(AValue: T): строка; функция класса GetValue(AName: string): T; Обратите внимание, что эти методы используют Generics (это бит T). Обобщения очень полезны, поскольку они позволяют вам написать функциональность один раз, а затем повторно использовать ее с разными типами в разное время в коде.
В этом случае универсальные методы TRttiEnumerationType предназначены для использования только с Enums, а не с другими типами классов, поскольку определенная функциональность специфична для Enum.
Чтобы преобразовать перечисление TCompass сейчас, после добавления RTTI для использования, будет выглядеть следующим образом.
S: = TRttiEnumerationType.GetName (D); ShowMessage (S); Преобразовать обратно из строки также проще.
D: = TRttiEnumerationType.GetValue (S); Насколько легче это читать! и поскольку нам нужно было объявить тип только один раз, у нас меньше шансов на глупые ошибки копирования-вставки в коде.
Вы можете использовать тот же подход, что и в верхней части этой страницы, используя GetEnumValue. Вы можете легко объявить кодовый блок следующим образом:
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;
Итак, вы знаете, как это сделать:
function StrToEnumTest(aStr:String):TEnumTest;
begin
result := TEnumTest(GetEnumValue(TypeInfo(TEnumTest),aStr));
end;
Но вы не хотите делать это таким образом? Зачем? Я хотел бы, чтобы мы могли сделать это:
inline function StrToEnumTest(aStr:String):<T>;
begin
result := <T>(GetEnumValue(TypeInfo(<T>),aStr));
end;