Версия для печати
Стандарт стилевого оформления исходного кода DELPHI
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=802Александр В. Ткаченко
дата публикации 05-06-2003 14:04Стандарт стилевого оформления исходного кода DELPHI
Содержание:
- ФАЙЛЫ ИСХОДНОГО КОДА
- СОГЛАШЕНИЕ ОБ ИМЕНОВАНИЯХ
- ИСПОЛЬЗОВАНИЕ ПРОБЕЛОВ
- КОММЕНТАРИИ
- КЛАССЫ
- ИНТЕРФЕЙСЫ
- ОПЕРАТОРЫ
- ДОПОЛНЕНИЯ
ВВЕДЕНИЕ Этот стандарт документирует стилевое оформление для форматирования исходного кода Delphi. Оригинал статьи создан Чарльзом Калвертом и расположен на "Borland Community site". В стандарте использованы материалы команды разработчиков Delphi, сообщества разработчиков библиотеки JEDI. Стандарт так же дополнен некоторыми правилами, созданными на основе собственного опыта разработки.
Object Pascal является замечательно спроектированным языком. Одним из его многочисленных достоинств является легкая читабельность. Предлагаемый стандарт позволит еще более повысить легкость чтения кода Object Pascal. Следование довольно простым соглашениям, приведенным в этом стандарте, позволит разработчикам понять, что унифицированное оформление намного повышает читабельность и понятность кода. Использование стандарта намного облегчит жизнь во время этапов разработки и тестирования, когда довольно часто приходится подменять друг друга и разбираться в чужом коде.
Процесс перехода с собственного стиля оформления на предлагаемый может оказаться непростым, но человеческий мозг довольно легко адаптируется к стандартам и находит пути для быстрого запоминания предлагаемых правил. В дальнейшем, следование стандарту не вызывает затруднений. Для более комфортабельного перехода на этот стандарт предлагается воспользоваться свободно распространяемой утилитой для форматирования исходных текстов "delforexp" (*).
Хочется отметить, что в компании Borland, на Web-сайте компании Borland, на CD, купленных у компании Borland, везде где есть исходный код, стандарт форматирования является законом.
Этот документ не является попыткой определить грамматику языка Object Pascal. Например, если Вы попытаетесь поставить точку с запятой перед выражением else, то компилятор не позволит Вам этого сделать. Этот документ говорит Вам, как нужно поступать, когда есть возможность выбора из многих вариантов при оформлении Вашего исходного кода.
ФАЙЛЫ ИСХОДНОГО КОДА Исходный код Object Pascal подразделяется на модули и файлы проекта, которые подчиняются одинаковым соглашениям. Файл проекта Delphi имеет расширение DPR. Этот файл является главным исходным файлом для всего проекта. Любые модули, используемые в проекте, всегда будут иметь расширение PAS. Дополнительные файлы, используемые в проекте (командные, html, DLL и т.д.) могут играть важную роль, но эта глава описывает форматирование только PAS и DPR файлов.
Именование исходных файлов
Язык Object Pascal поддерживает длинные имена файлов. Если при создании имени Вы используете несколько слов, то необходимо использовать заглавную букву для каждого слова в имени: MyLongName.pas. Этот стиль оформления известен как InfixCaps или CamelCaps. Расширения файлов должны быть в нижнем регистре. Исторически, некоторые исходные файлы Delphi именуются по шаблону 8.3, но в настоящее время разработчики не обязаны придерживаться этого ограничения.
Если Вы осуществляете перевод заголовочных файлов C/C++, то паскалевский эквивалент должен иметь тоже самое имя и расширение PAS. Например Windows.pas. Если правила грамматики языка Object Pascal требуют объединения нескольких транслированных файлов в один, то используйте имя того файла, в который Вы вкладываете остальные. Например: если WinBase.h вкладывается в Windows.h, то результирующее имя будет Windows.pas.
Все файлы модулей, созданные в организации ХХХ должны иметь префикс ХХХОрганизация исходных файлов
Все модули Object Pascal могут содержать следующие элементы в определенном порядке:Для визуального разделения элементов между ними должна быть хотя бы одна пустая строка.
- Информация о правах (Copyright/ID);
- Имя модуля (Unit Name);
- Объявление включаемых файлов (Include files);
- Секцию интерфейса (Interface section);
- Дополнительные определения (Additional defines);
- Объявление используемых модулей (Uses clause);
- Реализацию (Implementation)
- Объявление используемых модулей (Uses clause);
- Закрывающий оператор и точку (A closing end and a period).
Дополнительные элементы могут быть структурированы в порядке, который Вы сочтете нужным, но нужно соблюдать обязательные условия: в начале файла всегда копирайт, затем имя модуля, затем условные директивы и определения, директивы компилятора и файлы включения, затем определение подключений.
{************************************************************} { } { Модуль ХХХ } { Copyright (c) 2001 ООО ХХХХ } { отдел/сектор } { } { Разработчик: ХХ ХХ } { Модифицирован: 25 июня 2001 } { } {************************************************************} unit Buttons;Директивы компилятора не следует напрямую включать в исходный код. Для этого следует воспользоваться определением включений и подключить глобальный для проекта файл с директивами компилятора:
{$I NX.INC} interfaceВ случае необходимости, можно напрямую переопределить глобальные директивы компилятора. Следует помнить, что переопределяющие директивы должны быть документированы и Вы должны постараться ограничиться только локальным переопределением. Например для одной процедуры:
{$S-,W-,R-} {$C PRELOAD} interface uses Windows, Messages, Classes, Controls, Forms, Graphics, StdCtrls, ExtCtrls, CommCtrl;Секции определения типов и констант Вы можете располагать относительно друг друга как Вам угодно. Секция реализации должна начинаться с ключевого слова implementation, затем объявление используемых модулей (Uses clause), затем любые включение файлов или другие директивы.
implementation uses Consts, SysUtils, ActnList, ImgList; {$R BUTTONS.RES}Копирайт и комментарий
Пример заголовка для модуля:Следует обратить внимание на элементы заголовка:
{************************************************************} { } { Модуль ХХХ } { Copyright (c) 2001 ООО ХХХХ } { отдел/сектор } { } { Разработчик: ХХ ХХ } { Модифицирован: 25 июня 2001 } { } {************************************************************}
- Назначение модуля;
- Копирайт;
- Разработчик;
- Дата последней модификации для исполняемой версии.
Объявление модуля
Каждый исходный файл должен содержать объявление модуля. Слово unit является ключевым, поэтому оно должно быть написано в нижнем регистре. Имя модуля может содержать символы как в верхнем, так и в нижнем регистре и должно быть таким же, как и имя используемое для этого файла операционной системой. Например:
unit MyUnit;Этот модуль будет назван MyUnit.pas, когда он будет сохранен операционной системойОбъявление используемых модулей
Внутри модуля объявление используемых модулей должно начинаться со слова uses в нижнем регистре. Затем следуют наименования модулей с сохранением регистра символов:
uses MyUnit;Каждый используемый модуль должен отделяться от следующего с помощью запятой. Объявление используемых модулей должно заканчиваться точкой с запятой. Список используемых модулей необходимо располагать на следующей строке после слова uses. Если используются модули из разных проектов или производителей, то необходимо сгруппировать модули по проектам или производителям и каждую новую группу начинать с новой строки и снабжать комментариями:
Если список используемых модулей не умещается по ширине в 80 символов, то его необходимо перенести на следующую строку.
uses Windows, SysUtils, Classes, Graphics, Controls, Forms, TypInfo // модули Delphi , XХХMyUnit1, ХХXMyUnit2; // модули ХХХОбъявление классов и интерфейсов
Объявление класса начинается с двух пробелов, затем идет идентификатор класса с префиксом Т в нотации InfixCaps. Ни в коем случае в исходных файлах Object Pascal нельзя использовать табуляцию:
TMyClassСледом за идентификатором класса идет пробел, знак равенства, пробел и слово class в нижнем регистре:TMyClass = classЕсли необходимо определить родителя класса, то следует добавить открывающую скобку, имя класса-родителя и закрывающую скобку:TMyClass = class(TObject)Объявления областей видимости начинаются с двух пробелов и, следовательно, области видимости располагаются на одном уровне с идентификатором класса:
TMyClass = class(TObject) private protected public published end;Данные всегда должны располагаться только в приватной секции и названия переменных должны всегда начинаться с префикса F. Все объявления внутри класса должны начинаться с четырех пробелов:
TMyClass = class(TObject) private FMyData: Integer; function GetData: Integer; procedure SetData(Value: Integer); public published property MyData: Integer read GetData write SetData; end;Оформление объявлений интерфейсов подчиняется тем же правилам, что и оформление классов. Отличие будет в использовании ключевых слов специфичных для интерфейсов
СОГЛАШЕНИЕ ОБ ИМЕНОВАНИЯХ Исключая зарезервированные слова и директивы, которые всегда пишутся в нижнем регистре, все идентификаторы Object Pascal должны использовать InfixCaps:
MyIdentifier MyFTPClassСамое главное исключение для всех правил состоит в использовании оттранслированных заголовочных файлов С/С++. В этом случае всегда используются соглашения, принятые в файле источнике. Например будет использоваться WM_LBUTTONDOWN, а не wm_LButtonDown.
Для разделения слов нельзя использовать символ подчеркивания. Имя класса должно быть именем существительным или фразой с именем существительным. Имена интерфейсов или классов должны отражать главную цель их создания:
Правильно:AddressForm ArrayIndexOutOfBoundsExceptionНеправильно:ManageLayout (глагол) delphi_is_new_to_me (подчерк)Именование модулей
Смотрите пункт 2.1.Именование классов и интерфейсов
Смотри объявление классов и интерфейсов.Именование полей
При именовании полей всегда необходимо использовать InfixCaps. Всегда объявлять переменные только в приватных частях и использовать свойства для доступа к переменным. Для переменных использовать префикс F.
Имена процедур для установки/получения значений свойств должны составляться по правилу: для получения - Get+имя свойства; для установки - Set+имя свойства.
Правильно
- Не используйте все заглавные буквы для констант, за исключением оттранслированных заголовочных файлов.
- Не используйте Венгерскую нотацию, за исключением оттранслированных заголовочных файлов.
FMyString: string;НеправильноlpstrMyString: string;Исключение для Венгерской нотации делается в случае объявления перечислимого типа:TBitBtnKind = (bkCustom, bkOK, bkCancel, bkHelp, bkYes, bkNo, bkClose, bkAbort, bkRetry, bkIgnore, bkAll); bk обозначает ButtonKindКогда Вы раздумываете над именами переменных, то имейте в виду, что нужно избегать однобуквенных имен, кроме как для временных переменных и переменных цикла.
Переменные цикла именуются I и J. Другие случаи использования однобуквенных переменных это S (строка) и R (результат). Однобуквенные имена должны всегда использовать символ в верхнем регистре, но лучше использовать боле значимые имена. Не рекомендуется использовать переменную l (эль), потому что она похожа на 1 (единица).
Именование методов
При именовании полей всегда необходимо использовать стиль InfixCaps. Не допускается использование символов подчеркивания для разделения слов. В имени метода всегда должна содержаться команда к действию или глагольная фраза
Правильно:ShowStatus DrawCircle AddLayoutComponentНеправильно:MouseButton (Существительное, не описывает функцию) drawCircle (Начинается с маленькой буквы) add_layout_component (Используются символы подчерка) ServerRunning (Глагольная фраза, но без команды)Обратите внимание на последний пример (ServerRunning) - непонятно, что делает этот метод. Этот метод может использоваться для запуска сервера (лучше StartServer) или для проверки работы сервера (лучше IsServerRunning).
Методы для установки или получения значений свойств должны именоваться Get+имя свойства и - Set+имя свойства.
Например:GetHeight, SetHeighМетоды для теста/проверки булевских свойств класса должны именоваться с префиксом Is+имя свойства.
Например:IsResizable, IsVisibleИменование локальных переменных
Имена всех локальных переменных должны подчиняться тем же правилам, которые установлены для именования полей, исключая префикс F.
Зарезервированные слова
Зарезервированные слова и директивы должны быть все в нижнем регистре. Производные типы должны начинаться с большой буквы (Integer), однако string - это зарезервированное слово и оно должно быть в нижнем регистре.
Объявление типов
Все объявления типов должны начинаться с префикса Т и должны придерживаться правил, приведенных при описании оформления модуля или описании оформления класса.
ИСПОЛЬЗОВАНИЕ ПРОБЕЛОВ Использование пустых строк
Пустые строки могут повысить читабельность путем группирования секций кода, которые логически связаны между собой. Пустые строки должны использоваться в следующих местах:
- После блока копирайта;
- После декларации пакета;
- После секции импорта;
- Между объявлениями классов;
- Между реализациями методов;
Использование пробелов
Язык Object Pascal является очень легким для понимания языком, поэтому нет особой необходимости в использовании большого количества пробелов. Следующие пункты дадут Вам понимание того, в каком случае необходимо использовать пробелы.
Пробелы, запрещенные к использованию
Примеры правильного использования:
- До или после оператора .(точка);
- Между именем метода и открывающей скобкой;
- Между унарным оператором и его операндом;
- Между выражением приведения (cast) и приводимым выражением;
- После открывающей скобки или перед закрывающей;
- После открывающей квадратной скобки [ или перед закрывающей ];
- Перед точкой с запятой;
function TMyClass.MyFunc(var Value: Integer); MyPointer := @MyRecord; MyClass := TMyClass(MyPointer); MyInteger := MyIntegerArray[5];Примеры неправильного использования:function TMyClass.MyFunc( var Value: Integer ) ; MyPointer := @ MyRecord; MyClass := TMyClass ( MyPointer ) ; MyInteger := MyIntegerArray [ 5 ] ;Использование отступов
Всегда необходимо использовать два пробела для всех уровней отступа. Другими словами, первый уровень отступает на два пробела, второй на четыре и так далее. Никогда не используйте символы табуляции.
Существует несколько исключений из этого правила. Зарезервированные слова unit, uses, type, interface, implementation, initialization и finalization всегда должны примыкать к левой границе. Также должны быть отформатированы финальный end и end, завершающий исходный модуль. В файле проекта выравнивание по левой границе применяется к словам program, главным begin и end. Код внутри блока begin..end должен иметь отступ два символа.
Перенос строк
Все строки должны быть ограничены 80 столбцами. Строки, длиннее чем 80 столбцов должны быть разделены и перенесены. Все перенесенные строки должны быть выровнены по первой строке и иметь отступ в два символа. Выражение begin всегда должно находиться на своей отдельной строке.
Пример:
Правильно
function CreateWindowEx(dwExStyle: DWORD; lpClassName: PChar; lpWindowName: PChar; dwStyle: DWORD; X, Y, nWidth, nHeight: Integer; hWndParent: HWND; hMenu: HMENU; hInstance: HINST; lpParam: Pointer): HWND; stdcall;Никогда не разрывайте строку между параметром и его типом, кроме параметров, перечисляемых через запятую. Двоеточие для всех объявлений переменных не должно содержать перед собой пробелов и иметь один пробел после перед именем типа.
Правильноprocedure Foo(Param1: Integer; Param2: Integer);Неправильноprocedure Foo( Param :Integer; Param2:Integer );Нельзя переносить строки в тех местах, где не допускаются пробелы, например между именем метода и открывающей скобкой или между именем массива и открывающей квадратной скобкой. Никогда нельзя помещать выражение begin на строку, содержащую другой код.
НеправильноПравильно
while (LongExpression1 or LongExpression2) do begin // DoSomething // DoSomethingElse; end;while (LongExpression1 or LongExpression2) do begin // DoSomething // DoSomethingElse; end; if (LongExpression1) or (LongExpression2) or (LongExpression3) thenВ случае с логическими операторами предпочтительнее будет следующий вариант:
if (LongExpression1) or (LongExpression2) or (LongExpression3) then
КОММЕНТАРИИ Язык Object Pascal поддерживает два типа комментариев: блочные и однострочные. Общие соображение по использованию комментариев могут быть следующими:
- Помещайте комментарий недалеко от начала модуля для пояснения его назначения;
- Помещайте комментарий перед объявлением класса;
- Помещайте комментарий перед объявлением метода;
- Избегайте очевидных комментариев: (i := i + 1 // добавить к i единицу);
- Помните, что вводящий в заблуждение комментарий хуже чем его отсутствие;
- Избегайте помещать в комментарий информацию, которая со временем может быть не верна;
- Избегайте разукрашивать комментарии звездочками или другими символами;
- Для временных (отсутствующие в релизе) комментариев используйте "TODO".
Блочные комментарии
Object Pascal поддерживает два типа блочных комментариев. Наиболее часто используемый блочный комментарий - это пара фигурных скобок: { }. Команда разработчиков Delphi предпочитает использовать этот комментарий как можно проще и как запасной. Используйте в таких комментариях пробелы для форматирования текста и не используйте символы "зведочка" ( "*" ). При переносе строк необходимо сохранять отступы и выравнивание
Пример из DsgnIntf.pas:
{ TPropertyEditor Edits a property of a component, or list of components, selected into the Object Inspector. The property editor is created based on the type of the property being edited as determined by the types registered by... etc... GetXxxValue Gets the value of the first property in the Properties property. Calls the appropriate TProperty GetXxxValue method to retrieve the value. SetXxxValue Sets the value of all the properties in the Properties property. Calls the appropriate TProperty SetXxxxValue methods to set the value. }В блочный комментарий всегда заключается информация о модуле: копирайт, дата модификации и так далее. Блочный комментарий, описывающий метод должен идти перед объявлением метода.
ПравильноНеправильно
{ TMyObject.MyMethod This routine allows you to execute code. } procedure TMyObject.MyMethod; begin end;
procedure TMyObject.MyMethod; {****************************************************** TMyObject.MyMethod This routine allows you to execute code. *******************************************************} begin end;Второй тип блочного комментария содержит два символа: скобку и звездочку: (* *). Этот тип комментария используется при разработке исходного кода. Его преимуществом является то, что он поддерживает вложенные комментарии, правда комментарии должны быть разного типа. Вы можете использовать это свойство для комментирования больших кусков кода, в котором встречаются другие комментарии:
(* procedure TForm1.Button1Click(Sender: TObject); begin DoThis; // Start the process DoThat; // Continue iteration { We need a way to report errors here, perhaps using a try finally block ??? } CallMoreCode; // Finalize the process end; *)Однострочные комментарии
Однострочный комментарий состоит из символов // со следующим за ними текстом комментария. После символов // должен идти пробел и затем текст. Однострочные комментарии должны иметь отступы такие же, как и код, в котором они встречаются. Однострочные комментарии можно сгруппировать, чтобы сформировать большой комментарий.
Однострочный комментарий может начинаться с новой строки и может продолжать код, который он комментирует. В этом случае между кодом и комментарием должен быть хотя бы один пробел. Если больше одного комментария следует за кодом, то они должны быть выровнены по одному столбцу.
Пример однострочного строкового комментария:Пример комментария в коде:
// Open the table Table1.Open;Необходимо избегать использовать комментарии в коде для каждой строки модуля.
if (not IsVisible) then Exit; // nothing to do Inc(StrLength); // reserve space for null terminator
КЛАССЫ Структура тела класса
Тело класса при его декларации подчинено следующей структуре:Поля, свойства и методы в вашем классе должны быть упорядочены в алфавитном порядке.
- Объявление полей;
- Объявление методов;
- Объявление свойств.
Уровни доступа
Исключая код, вставленный IDE, директивы видимости должны быть объявлены в следующем порядке:
- Приватные (скрытые) члены класса (private);
- Защищенные члены класса (protected);
- Общедоступные члены класса (public);
- Публикуемые члены класса (published)
Таким образом, в Object Pascal существует четыре уровня доступа для членов класса: published, public, protected и private - в порядке уменьшения видимости. По умолчанию, уровень доступа - published. В общем, члены класса должны давать наименьший уровень доступа, который подходит для этого члена. Например, член, к которому имеют доступ классы из одного модуля должен иметь уровень доступа private. Кроме того, объявляя члены класса с наименьшим уровнем доступа, Вы позволяете компилятору воспользоваться дополнительными возможностями для оптимизации. С другой стороны, если Вы планируете в дальнейшем порождать дочерние классы от Вашего класса, то нужно использовать уровень доступа protected.
Никогда не указывайте уровень доступа public для данных. Данные всегда должны быть объявлены в приватной секции и доступ к ним должен осуществляться с помощью методов или свойств.
Объявление конструктора
Все методы класса должны быть упорядочены по алфавиту. Однако Вы можете поместить объявления конструктора и деструктора перед всеми остальными методами. Если у класса существует более чем один конструктор и если они имеют одинаковые имена, то они должны располагаться в порядке увеличения числа параметровОбъявление методов
По возможности, объявление метода должно располагаться на одной строке:
Например:
procedure ImageUpdate(Image img, infoflags: Integer, x: Integer, y: Integer, w: Integer, h: Integer)
ИНТЕРФЕЙСЫ Все основные правила форматирования для классов применяются и для форматирования интерфейсов. Интерфейсы декларируются в той же манере, что и классы.
InterfaceName = interface([Inherited Interface]) InterfaceBody end;Отступ для интерфейса должен быть равен двум пробелам. Тело интерфейса имеет отступ четыре пробела. Закрывающий end должен иметь отступ в два пробела. Объявление класса заканчивается точкой с запятой. У интерфейса не существует полей, однако свойства могут присутствовать.
Все методы интерфейса являются абстрактными и общедоступными, поэтому не требуется включать слова public и abstract в объявление метода.
Структура тела интерфейса
Тело интерфейса при его декларации подчинено следующей структуре:Стили для объявления свойств и методов интерфейса аналогичным стилям для класса.
- Объявление методов интерфейса;
- Объявление свойств интерфейса.
ОПЕРАТОРЫ Операторы - это одна или более строк кода, разделенных точкой с запятой. Простые операторы имеют одну точку с запятой, а составные могут иметь более чем одну точку с запятой и, таким образом, состоят из множества простых операторов.
Это простой оператор:A := B;Это составной или структурированный оператор:begin B := C; A := B; end;Простые операторы
Простые операторы содержат одну точку с запятой. Если Вам необходимо разделить операторы, то перенесите продолжение оператора на следующую строку с отступом в два пробела:
MyValue := MyValue + (SomeVeryLongStatement / OtherLongStatement);Составные операторы
Составные операторы всегда заканчиваются точкой с запятой.begin MyStatement; MyNext Statement; MyLastStatement; end;Присвоения и выражения
Каждое присвоение и каждое выражение должно располагаться на разных строках.
Правильноa := b + c; Inc(Count);Неправильноa := b + c; Inc(Count);Объявление локальных переменных
Локальные переменные должны иметь стиль Camel Caps. Для локальных переменных префикс F не требуется.var MyData: Integer; MyString: string;Все переменные с их типами, особенно поля класса, должны быть объявлены на различных строках.Объявление массивов
В объявлении массива перед и после квадратных скобок должны стоять пробелы.type TMyArray = array [0..100] of Char;Оператор if
Оператор if всегда должен располагаться по крайней мере на двух строках
Неправильноif A < B then DoSomething;Правильноif A < B then DoSomething;В случае составного оператора необходимо поместить каждый оператор на новую строку.
НеправильноПравильно
if A < B then begin DoSomething; DoSomethingElse; end else begin DoThis; DoThat; end;
if A < B then begin DoSomething; DoSomethingElse; end else begin DoThis; DoThat; end;Все остальные варианты расположения операторов не рекомендуются и не одобряются, хотя и являются синтаксически правильными. Избегайте использования круглых скобок в простых проверках. Например:
Правильноif I > 0 then DoSomething;Неправильноif (I > 0) then DoSomething;Оператор for
НеправильноПравильно
for i := 0 to 10 do begin DoSomething; DoSomethingElse; end;
for i := 0 to 10 do begin DoSomething; DoSomethingElse; end; for I := 0 to 10 do DoSomething;Оператор while
НеправильноПравильно
while x < j do begin DoSomething; DoSomethingElse; end;
while x < j do begin DoSomething; DoSomethingElse; end; while x < j do Something;Оператор repeat until
Правильно
repeat x := j; j := UpdateValue; until j > 25;Оператор case
Несмотря на то, что существует множество синтаксически правильных конструкций, одобренной и рекомендованной считается следующая:
Правильно
case ScrollCode of SB_LINEUP, SB_LINEDOWN: begin Incr := FIncrement div FLineDiv; FinalIncr := FIncrement mod FLineDiv; Count := FLineDiv; end; SB_PAGEUP, SB_PAGEDOWN: begin Incr := FPageIncrement; FinalIncr := Incr mod FPageDiv; Incr := Incr div FPageDiv; Count := FPageDiv; end; else Count := 0; Incr := 0; FinalIncr := 0; end;Оператор try
Несмотря на то, что существует множество синтаксически правильных конструкций, одобренной и рекомендованной считается следующая:
Правильно
try try EnumThreadWindows(CurrentThreadID, @Disable, 0); Result := TaskWindowList; except EnableTaskWindows(TaskWindowList); raise; end; finally TaskWindowList := SaveWindowList; TaskActiveWindow := SaveActiveWindow; end;
ДОПОЛНЕНИЯ В этой части собраны дополнения, которые не вошли в стандарт Borland. Эти дополнения взяты из правил JCL и опыта российских разработчиков.
Const, Var и Type
Зарезервированные слова var, const и type всегда пишутся на новой строке и не допускают появления на этой же строке какого-либо текста.
ПравильноНеправильно
type TMyType = Integer; const MyConstant = 100; var MyVar: Integer;
type TMyType = Integer; const MyConstant = 100; var MyVar: Integer;Процедуры должны иметь только по одной секции type, const и var в следующем порядке:
procedure SomeProcedure; type TMyType = Integer; const ArraySize = 100; var MyArray: array [1..ArraySize] of TMyType; begin ... end;Директивы условной компиляции
Все директивы условной компиляции должны быть собраны в одном модуле ХХX.INC. Этот файл предназначен для определения глобальных директив. Оператор include должен быть помещен между ключевыми словами unit и interface. Никто не может модифицировать файл ХХX.INC по собственному желанию.
Строковые ресурсы
Все строковые ресурсы должны иметь вид "Rs"[Category][Name]. [Category] должно быть аббревиатурой или названием категории кода, где используется строка. [Name] должно быть именем строки ресурса. Например, конструктор TJclCriticalSectionEx.CreateEx вызывает исключительную ситуацию при ошибке инициализации. Сообщение об ошибке объявляется в глобальном модуле ХХXResources.pas с именем RsynchInitCriticalSection.
Все строки должны быть исключены из кода и заменены на константы. Исключением из этого правила являются строки, которые являются какими-либо командами или от них будет зависеть поведение экземпляров класса. Такие строки должны быть явно объявлены в каком-либо из методов класса.
Исключения
Все исключения должны начинаться с префикса EХХХ. Все исключения должны быть отнаследованны от класса ENхError. При возбуждении исключительной ситуации предпочтительным является ее создание с помощью метода CreateRes:
raise EХХХSomeException.CreateRes(@RsSomeResourceString);Категории и разделение алгоритмов
Обычно, содержимое каждого созданного модуля есть набор классов, функций и процедур, принадлежащих к одной категории. Например, ХХХLogin содержит все, что относится к идентификации и персонификации пользователя. Для ясного восприятия исходного кода следует придерживаться следующего правила: в интерфейсной части модуля каждая группа функций, относящихся к одной субкатегории должны отделяться от другой группы функций тремя строками шириной 80 столбцов с описанием субкатегории на второй строке:
1 2 Информация о последней попытке идентификации 3 procedure GetLastUserName(var ZUser: string); procedure GetLastDatabase(var ZDatabase: string);В секции реализации каждая подкатегория или класс должен разделяться строкой, состоящей из символов равенства (=), закомментированных однострочным комментарием и пустой строкой перед и после группы функций:
//================================================= procedure GetLastUserName(var ZUser: string); begin ... end; procedure GetLastDatabase(var ZDatabase: string); begin ... end; //==================================================Каждая функция из одной группы или методы класса должны разделяться между собой строкой, состоящей из символов минуса (-), закомментированных однострочным комментарием и пустой строкой перед и после функции или метода:
//================================================== procedure GetLastUserName(var ZUser: string); begin ... end; //-------------------------------------------------- procedure GetLastDatabase(var ZDatabase: string); begin ... end; //==================================================Ассемблер
Локальные процедуры
Локальные функции и процедуры должны иметь стандартный отступ в два пробела вправо от их владельца и сама процедура должна выделяться пустыми строками по одной перед и после локальной процедуры. Если "внешняя" процедура имеет локальные переменные, то они должны декларироваться перед локальной процедурой, независимо от того, будет ли в локальной процедуре осуществляться доступ к ним или нет. Однако общие соображения таковы, что локальных процедур следует избегать.
procedure SomeProcedure; var I: Integer; procedure LocalProcedure; begin ... end; begin ... LocalProcedure; ... end;Объявление параметров
Когда объявляется список параметров для процедуры, функции или метода пользуйтесь следующими рекомендациями:
- Комбинируйте формальные параметры одного типа в одно выражение;
- Не используйте префикс А, кроме случаев, когда вызывается метод класса, который работает со свойством, которе имеет идентичное имя;
- Придерживайтесь следующего порядка в параметрах: сначала входные параметры, затем входные/выходные, затем выходные. Параметры, имеющие значение по умолчанию по правилам Object Pascal помещаются в конец списка;
- Используйте const для параметров, которые не изменяются при работе вызываемых методов, процедур или функций.
Инициализация глобальных переменных
Глобальные переменные, как и члены класса всегда инициализируются нулем. Это трудно для понимания в случае разных типов. Например Integer инициализируется в 0, а pointer в nil. Для этого рекомендуется указывать в комментарии как инициализируется переменная.
var MyGlobalVariable: Pointer // = nil;Несмотря на то, что глобальные переменные разрешены языком Object Pascal, используйте их лишь в самых крайних случаях.
Перевод с английского и подготовка материала: Александр В. Ткаченко
Специально для Королевства Delphi
(*) см. описание утилиты в разделе Генераторы кода