В этой теме будут выкладываться и обсуждаться синтаксические преимущества PascalABC.NET перед C# !
Статические индексные свойства по умолчанию
Уникальными по сравнению с C# кажутся статические индексные свойства (по умолчанию). В C# нет даже просто статических индексаторов, отчего простейший для PascalABC.NET код:
type
T = class
private static property _prop[ind: integer]: integer read Arr(1, 2, 3)[ind];
end;
Для C# оказывается невозможным.
Но фича не была бы фичей, если бы от неё не было толку! Поговорим о применении статических индексных свойств по умолчанию. Эта конструкция очень полезна, когда есть объекты типа T и к ним нужен удобный доступ. Например, если в вашей программе есть база данных городов, можно написать следующий код:
type
Town = class
private fPop: uint64;
public constructor(Pop: uint64) := fPop := Pop;
public property Population: uint64 read fPop;
private static ftowns: Dictionary<string, Town>;
private static property _towns[ind: string]: Town read ftowns[ind] write ftowns[ind] := value; default;
public static procedure Init;
begin
//Заполнение может быть из файла, с клавиатуры, да вообще как угодно
ftowns := new Dictionary<string, Town>;
ftowns.Add('Челябинск', new Town(3490000));
ftowns.Add('Ростов', new Town(1100000));
ftowns.Add('Владивосток', new Town(600000));
end;
private static constructor := Init;
end;
И мы сможем обратиться к городу просто Town[‘townname’]!
begin
Writeln(Town['Челябинск'].Population);
end.
Теперь о применении на практике. В одной из реализаций одного своего проекта весь текст, который я использовал в интерфейсе программы, хранился в одном классе. Вот так выглядел тот класс:
type
Text = static class
private static filename := 'bin\textdb.dat';
private static fText: array of string;
private static fTextCount: integer;
private static property ffText[ind: integer]: string read fText[ind] write fText[ind] := value; default;
public static procedure ReloadText;
begin
//Здесь происходило заполнение
end;
end;
И пример обращения:
Console.SetCursorPosition(52, 5 + id); write($'{Text[5200]}: {Savegame.Saves[Stage].Player.Nickname}');
Console.SetCursorPosition(52, 6 + id); write($'{Text[5201]}: {Savegame.Saves[Stage].Player.Level}');
Console.SetCursorPosition(52, 7 + id); write($'{Text[5202]}: {Savegame.Saves[Stage].Player.Experience} / {Player.fNeedExp(Savegame.Saves[Stage].Player.Level)}');
Console.SetCursorPosition(52, 8 + id); write($'{Text[5203]}: {Savegame.Saves[Stage].Player.FreePerks}');
Console.SetCursorPosition(52, 9 + id); write($'{Text[5204]}: {Savegame.Saves[Stage].Player.Money / 100} {Text[299]}');
Console.SetCursorPosition(52, 10 + id); write($'{Text[5205]}: {Map[Savegame.Saves[Stage].Player.Position].Type.Name} {Map[Savegame.Saves[Stage].Player.Position].Name}');
Как эта часть Text выглядела в базе данных:
00005200 Ник
00005201 Уровень
00005202 Опыт
00005203 Нераспределённые очки
00005204 Деньги
00005205 Местоположение
Так как информация использовалась разными модулями, её нельзя было хранить в локальных переменных-массивах. Использование статических индексных свойств по умолчанию облегчило понимание и написание кода, а также повысило удобство.