Delphi. Немного об использовании string в CASE

Каждый разработчик для улучшения понимания кода программы, пытается повысить её читабельность. Один из вариантов это сделать — использовать оператор case при тестировании значения переменной. Но, к сожалению, в Delphi этот оператор умеет работать не со всеми типами переменных. Например, он не будет работать со строками. А что делать, если всё-таки нужно проверять переменную типа string оператором case? Давайте рассмотрим один из вариантов, как это можно сделать.
Тема сама по себе старая и известная, но, почему-то, она поднимается вновь и вновь. Кажется, достаточно открыть документацию к Delphi и увидеть, что там написано английским по «белому»:
1
2
3
4
5
6
7
8
|
<pre class="inline:true decode:1 " >Case Statements
The case statement may provide a readable alternative to deeply nested if conditionals. A case statement has the form:
case selectorExpression of
caseList1: statement1;
...
caseListn: statementn;
end
where selectorExpression is any expression of an ordinal type smaller than 32 bits (string types and ordinals larger than 32 bits are invalid)
|
И всё становится ясным: string types are invalid! Ну, нельзя сделать CASE по string! И всё.
Однако….
Если припомнить, что основная задача оператора CASE — повышение читабельности кода программы. Что собственно и подтверждено в процитированном выше фрагменте HELP’а The case statement may provide a readable alternative to deeply nested if conditionals. И посмотреть на вопрос об использовании string в CASE уже с этой точки зрения, то возникает совсем другое дизайнерское решение!
И так, предположим, переменная типа string, которую хочется использовать в CASE, может принимать значения: ‘english’, ‘deutsch’, ‘русский’ или ‘français’.
А раз, все строковые значения переменной можно перечислить, то почему бы не воспользоваться перечислимым типом для этого, ведь с перечислимым типом оператор CASE работает прекрасно:
1
2
|
type
TStringSet = (english, deutsch, русский, français);
|
И смотрится оператор CASE в таком случае почти как «по string»:
1
2
3
4
5
6
7
8
|
case ... of
english : showmessage('выбрано english');
deutsch : showmessage('выбрано deutsch');
русский : showmessage('выбрано русский');
français : showmessage('выбрано français');
else
showmessage('....');
end;
|
Остаётся лишь научиться находить элемент перечислимого типа, который по написанию совпадает со значением строковой переменной — фактически выполнить преобразование строки в элемент перечислимого типа, если такой, конечно, существует. Необходимый инструмент для этого находятся в unit TypInfo, а общая схема действий вырисовывается примерно следующая:
Остаётся лишь научиться находить элемент перечислимого типа, который по написанию совпадает со значением строковой переменной — фактически выполнить преобразование строки в элемент перечислимого типа, если такой, конечно, существует. Необходимый инструмент для этого находятся в unit TypInfo, а общая схема действий вырисовывается примерно следующая:
1
2
3
4
5
6
7
8
9
10
|
uses TypInfo;
type
TStringSet = (english, deutsch, русский, français);
...
var
StrVal : TStringSet;
s : string
....
s := 'русский';
StrVal := TStringSet(GetEnumValue(TypeInfo(TStringSet), s ) );
|
Ну и «на десерт» остаётся добавить фрагмент работающего кода:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
uses TypInfo;
type
TStringSet = (english, deutsch, русский, français);
procedure UseCase(str : string);
var
StrVal : TStringSet;
begin
StrVal := TStringSet(GetEnumValue(TypeInfo(TStringSet), str));
case StrVal of
english : showmessage('выбрано english');
deutsch : showmessage('выбрано deutsch');
русский : showmessage('выбрано русский');
français : showmessage('выбрано français');
else
showmessage('....');
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
UseCase('français');
end;
|
А все остальные нюансы и «специи» добавляются по вкусу.