Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Enum to string и обратно / 25 сообщений из 42, страница 1 из 2
02.02.2021, 18:15
    #40040953
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
А как бы проще организовать конвертацию энумератора в строку и обратно для таких конечных строк
'lower', 'upper', 'title', 'none', 'assume-lower', 'assume-title', 'assume-upper'?

Функции GetEnumName/GetEnumValue не подходят, т.к. конечные строки содержат знак "-" и я не объявлю такие идентификаторы

Таких энумераторов много, так что не очень хочется под каждый писать отдельные функции конвертации

С уважением, Vasilisk
...
Рейтинг: 0 / 0
02.02.2021, 18:25
    #40040955
Гаджимурадов Рустам
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
Напиши свою функцию. Ну или класс, если
требуется что-то большее, чем просто имена.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
02.02.2021, 18:28
    #40040956
Kazantsev Alexey
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
_Vasilisk_,

System.TypInfo.AddEnumElementAliases
...
Рейтинг: 0 / 0
02.02.2021, 18:30
    #40040957
Гаджимурадов Рустам
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
> System.TypInfo.AddEnumElementAliases

Ух-ты, круто...
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
02.02.2021, 19:04
    #40040971
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
Kazantsev Alexey
System.TypInfo.AddEnumElementAliases
GetEnumValue заработало. GetEnumName возвращает оригинальное имя
...
Рейтинг: 0 / 0
02.02.2021, 19:38
    #40040979
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
Альтенативный вопрос
Код: pascal
1.
TTestEnum = ([CustomName('b')] a)


Можно ли получить TRttiType для элемента перечисления, чтобы потом у него вызвать GetAttributse()?
...
Рейтинг: 0 / 0
02.02.2021, 21:25
    #40040988
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
Родилaсь такая структура
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
type
  TEnumAliasesManager<T> = record
  strict private
    type
      TEnumValue = record
      case TOrdType of
        otSByte: (SByte: ShortInt);
        otUByte: (UByte: Byte);
        otSWord: (SWord: SmallInt);
        otUWord: (UWord: Word);
        otSLong: (SLong: Integer);
        otULong: (ULong: Cardinal);
      end;
      PEnumValue = ^TEnumValue;
  strict private
    class var
      FAliases: TArray<string>;
  strict private
    class procedure CheckRegistered; static;
    class procedure SizeError; static; inline;
    class function IndexOf(const AStr: string): Integer; static;
  public
    class procedure Register(const AAliases: array of string); static;
    class function EnumToString(const AVal: T): string; static;
    class function StringToEnum(const AVal: string): T; static;
  end;

  EEnumAliasesManagerError = class(Exception);

class procedure TEnumAliasesManager<T>.CheckRegistered;
begin
  if FAliases = nil then
    raise EEnumAliasesManagerError.Create('No aliases registered');
end;

class procedure TEnumAliasesManager<T>.SizeError;
begin
  raise EEnumAliasesManagerError.Create('Unknown enumeration size');
end;

class function TEnumAliasesManager<T>.IndexOf(const AStr: string): Integer;
begin
  for Result := 0 to Length(FAliases) - 1 do begin
    if AStr = FAliases[Result] then
      Exit;
  end;
  raise EEnumAliasesManagerError.CreateFmt('Alias "%s" not found', [AStr]);
end;

class procedure TEnumAliasesManager<T>.Register(
  const AAliases: array of string);
var
  LTypeInfo: PTypeInfo;
  LMinValue: Integer;
  LMaxValue: Integer;
  LLen: Integer;
begin
  LTypeInfo := TypeInfo(T);
  if LTypeInfo^.Kind <> tkEnumeration then
    raise EEnumAliasesManagerError.Create('Type must be Enumeration');
  if LTypeInfo^.Kind <> tkEnumeration then
    raise Exception.Create('Type must be Enumeration');
  LMinValue := LTypeInfo^.TypeData^.MinValue;
  if LMinValue < 0 then begin  // WordBool, LongBool etc
    LMinValue := 0;
    LMaxValue := 1
  end else
    LMaxValue := LTypeInfo^.TypeData^.MaxValue;

  LLen := Length(AAliases);
  if LMaxValue - LMinValue + 1 <> LLen then
    raise Exception.Create('Invalid aliases size');

  SetLength(FAliases, LLen);
  TArray.Copy<string>(AAliases, FAliases, LLen);
end;

class function TEnumAliasesManager<T>.EnumToString(const AVal: T): string;
var
  LTypeInfo: PTypeInfo;
  LEnumVal: PEnumValue;
begin
  CheckRegistered;
  LTypeInfo := TypeInfo(T);
  LEnumVal := @AVal;
  case LTypeInfo^.TypeData^.OrdType of
    otSByte: Result := FAliases[LEnumVal^.SByte];
    otUByte: Result := FAliases[LEnumVal^.UByte];
    otSWord: Result := FAliases[LEnumVal^.SWord];
    otUWord: Result := FAliases[LEnumVal^.UWord];
    otSLong: Result := FAliases[LEnumVal^.SLong];
    otULong: Result := FAliases[LEnumVal^.ULong];
  else
    SizeError;
  end;
end;

class function TEnumAliasesManager<T>.StringToEnum(const AVal: string): T;
var
  LTypeInfo: PTypeInfo;
  LEnumVal: PEnumValue;
  LIdx: Integer;
begin
  CheckRegistered;
  LIdx := IndexOf(AVal);
  LTypeInfo := TypeInfo(T);
  LEnumVal := @Result;
  case LTypeInfo^.TypeData^.OrdType of
    otSByte: LEnumVal^.SByte := LIdx;
    otUByte: LEnumVal^.UByte := LIdx;
    otSWord: LEnumVal^.SWord := LIdx;
    otUWord: LEnumVal^.UWord := LIdx;
    otSLong: LEnumVal^.SLong := LIdx;
    otULong: LEnumVal^.ULong := LIdx;
  else
    SizeError;
  end;
end;

и использование
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
type
  TTestEnum1 = (en11, en12);
  TTestEnum2 = (en21, en22, en23);

procedure TForm1.Button1Click(Sender: TObject);
var
  LStr: string;
  LEn1: TTestEnum1;
  LEn2: TTestEnum2;
begin
  TEnumAliasesManager<TTestEnum1>.Register(['a', 'b']);
  TEnumAliasesManager<TTestEnum2>.Register(['x', 'y', 'z']);
  LStr := TEnumAliasesManager<TTestEnum1>.EnumToString(en12);
  LStr := TEnumAliasesManager<TTestEnum2>.EnumToString(en23);
  LEn1 := TEnumAliasesManager<TTestEnum1>.StringToEnum('b');
  LEn2 := TEnumAliasesManager<TTestEnum2>.StringToEnum('z');
end;

...
Рейтинг: 0 / 0
03.02.2021, 09:50
    #40041054
X11
X11
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
Kazantsev Alexey
_Vasilisk_,

System.TypInfo.AddEnumElementAliases


http://docwiki.embarcadero.com/Libraries/Sydney/en/System.TypInfo.AddEnumElementAliases

а справки и примеров нет :(
...
Рейтинг: 0 / 0
03.02.2021, 12:27
    #40041097
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
_Vasilisk_,

Ммм?
Код: pascal
1.
2.
3.
4.
  if LTypeInfo^.Kind <> tkEnumeration then
    raise EEnumAliasesManagerError.Create('Type must be Enumeration');
  if LTypeInfo^.Kind <> tkEnumeration then
    raise Exception.Create('Type must be Enumeration');
...
Рейтинг: 0 / 0
03.02.2021, 12:37
    #40041099
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
alekcvp,

вдруг просочится?
...
Рейтинг: 0 / 0
03.02.2021, 18:39
    #40041315
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
alekcvp
Ммм?
Рука дрогнула. Дважды Ctrl-V нажал :)
...
Рейтинг: 0 / 0
03.02.2021, 21:57
    #40041371
bk0010
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
wadman
alekcvp,

вдруг просочится?
И такое бывало (в смысле, приходилось писать по 2 одинаковых проверки подрят). На Lotus Notes, ЕМНИП.
...
Рейтинг: 0 / 0
04.02.2021, 09:46
    #40041438
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
_Vasilisk_,

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
    LTypeInfo := TypeInfo(T);
  if LTypeInfo^.Kind <> tkEnumeration then
    raise EEnumAliasesManagerError.Create('Type must be Enumeration');

  LMinValue := LTypeInfo^.TypeData^.MinValue;
  if LMinValue < 0 then begin  // WordBool, LongBool etc
    LMinValue := 0;
    LMaxValue := 1
  end else
    LMaxValue := LTypeInfo^.TypeData^.MaxValue;


я бы такие проверки в конструктор класса убрал, это и быстрее и проверка будет при запуске, а не при использовании
...
Рейтинг: 0 / 0
04.02.2021, 10:16
    #40041450
defecator
Модератор форума
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
kealon(Ruslan)
_Vasilisk_,

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
    LTypeInfo := TypeInfo(T);
  if LTypeInfo^.Kind <> tkEnumeration then
    raise EEnumAliasesManagerError.Create('Type must be Enumeration');

  LMinValue := LTypeInfo^.TypeData^.MinValue;
  if LMinValue < 0 then begin  // WordBool, LongBool etc
    LMinValue := 0;
    LMaxValue := 1
  end else
    LMaxValue := LTypeInfo^.TypeData^.MaxValue;



я бы такие проверки в конструктор класса убрал, это и быстрее и проверка будет при запуске, а не при использовании


а я не люблю в конструкторе никаких исключений поднимать
...
Рейтинг: 0 / 0
04.02.2021, 10:39
    #40041458
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
А я задачу, аналогичную задаче ТC, сделал через helper, реализовал в нем .ToString для enum и всё работает)
...
Рейтинг: 0 / 0
04.02.2021, 16:03
    #40041680
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
kealon(Ruslan)
я бы такие проверки в конструктор класса убрал, это и быстрее и проверка будет при запуске, а не при использовании
О! Спасибо за идею!
asutp2
А я задачу, аналогичную задаче ТC, сделал через helper, реализовал в нем .ToString для enum и всё работает)
Замечательно! А если энумераторов десяток? Десять хелперов?
...
Рейтинг: 0 / 0
04.02.2021, 16:34
    #40041704
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
kealon(Ruslan)
я бы такие проверки в конструктор класса убрал,
Компилятор напутал с очередностью вызова классовых конструкторов. В итоге классовый конструктор, откуда идет вызов метода
Код: pascal
1.
TEnumAliasesManager<T>.Register

вызывается раньше чем классовый конструктор
Код: pascal
1.
TEnumAliasesManager<T>.Create;

Т.е. проверку нужно вставлять в двух местах: и в конструкторе и в методе
...
Рейтинг: 0 / 0
04.02.2021, 19:41
    #40041803
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
_Vasilisk_
kealon(Ruslan)
я бы такие проверки в конструктор класса убрал,
Компилятор напутал с очередностью вызова классовых конструкторов.

есть простое правило: "если программа работает неправильно, значит ты что-то неправильно написал"
...
Рейтинг: 0 / 0
04.02.2021, 20:59
    #40041828
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
kealon(Ruslan)
есть простое правило: "если программа работает неправильно, значит ты что-то неправильно написал"
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
interface

type
  TClass1<T> = class
  strict private
    class constructor Create;
  public
    class procedure Method; static;
  end;

  TClass2 = class
  strict private
    class constructor Create;
  end;

implementation

class constructor TClass1<T>.Create;
begin
  ShowMessage(ClassName + '.Create');
end;

class procedure TClass1<T>.Method; 
begin
  ShowMessage(ClassName + '.Method');
end;

class constructor TClass2.Create;
begin
  ShowMessage(ClassName + '.Create');
  TClass1<Byte>.Method;
end;

Запускаю и вижу
TClass2.Create
TClass1<Byte>.Method
TClass1<Byte>.CreateНу конечно же я что-то неправильно написал
...
Рейтинг: 0 / 0
04.02.2021, 21:42
    #40041839
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
_Vasilisk_,

Наверное это потому что ты вызываешь метод класса из конструктора другого класса, нет?..
Никто не обещал что конструктор будет вызываться при любом обращении к классу.

Более того, если прочитать справку то там, внезапно, написано:
Note: Even though the compiler takes care of ordering the initialization of classes, in some complex scenarios, ordering may become random. This happens when the class constructor of a class depends on the state of another class that, in turn, depends on the first class.
У тебя класс2 зависит от класса1, потому что он вызывает его методы, а класс1 зависит от класса2, потому что это дженерик и до первого обращения к нему с указанием типа его вообще не существует.

Более того, дальше тебя ждёт ещё больше сюрпризов, потому что:
Note: The class constructor for a generic class or record may execute multiple times. The exact number of times the class constructor is executed in this case depends on the number of specialized versions of the generic type. For example, the class constructor for a specialized TList<String> class may execute multiple times in the same application.
...
Рейтинг: 0 / 0
05.02.2021, 10:53
    #40041987
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
alekcvp,

1-е верно, компилятор может упустить вызов конструктора если он например может его выкинуть
или если "не видит" связи между вызовами - запустить его как получится


авторNote: The class constructor for a generic class or record may execute multiple times. The exact number of times the class constructor is executed in this case depends on the number of specialized versions of the generic type. For example, the class constructor for a specialized TList<String> class may execute multiple times in the same application. а вот это неправда, там такой же счётчик как и у Unit-ов. Эту багу хорошо повыправляли

на 10-ке

Код: plaintext
1.
2.
3.
TClass1<System.Byte>.Create
TClass2.Create
TClass1<System.Byte>.Method
...
Рейтинг: 0 / 0
05.02.2021, 11:05
    #40041996
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
kealon(Ruslan)
а вот это неправда, там такой же счётчик как и у Unit-ов. Эту багу хорошо повыправляли

Это цитата из справки, если что. Причём из справки для 10.4.
Так что если ты с чем-то не согласен - пиши сразу в Эмбу 😁
...
Рейтинг: 0 / 0
05.02.2021, 11:35
    #40042012
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
alekcvp,

и что же я им напишу, верните багу назад в соответствии с этой документацией?
...
Рейтинг: 0 / 0
05.02.2021, 11:38
    #40042013
asutp2
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
Столько проблем, хотя в варианте с хелпером все работает предсказуемо и без багов)))
...
Рейтинг: 0 / 0
05.02.2021, 11:57
    #40042024
kealon(Ruslan)
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Enum to string и обратно
asutp2,

да я кажется знаю где у _Vasilisk_ бага, он как-то просил пример по одному вопросу "почему так делать нельзя", похоже он сам его и написал
но пока не видно как он его использует, однозначно утверждать нельзя
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Enum to string и обратно / 25 сообщений из 42, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]