Содержание
- Первая страница
- Редактор кода
- Рефакторинг
- Unit-тестирование
- Компилятор
- Отладка
- Встроенный Data Explorer
Первая страница
После загрузки среды перед нами возникает приветственная страница "Welcome Page". Это новый аналог того самого окошка новостей, которое выглядело довольно неказисто, если ваш компьютер не был подключен к интернету во время работы. Однако не стоит так же сбрасывать со счетов и новый вариант. Кроме ленты новостей (RSS), "Welcome Page" содержит немало полезных ссылок. Во-первых, в самом верху страницы перечислен список проектов, которые вы уже открывали некоторое время назад, с указанием даты последней модификации. Каждая ссылка, естественно, открывает выбранный проект.
Показать скриншот в отдельном окне
В левой части страницы подобраны ссылки на справочную информацию, документацию, которая устанавливается на ваш компьютер при инсталяции Delphi2005. Далее идут ссылки в интернет, на страницы компаний-разработчиков, чьи продукты встроены в среду. Например, на страницу Rave Reports, IntraWeb и так далее. И, наконец, ссылки на новостные группы в интернете, BDN и другие страницы Borland-ресурсов.
То есть, "Welcome Page", действительно содержит полезную информацию. Может быть, не часто придется ею пользоваться, но и забывать о ней не стоит, может пригодиться.
Среда предоставляет возможнсть работать как в классическом стиле предыдущих версий Delphi (с отдельными окнами для дизайнера форм, инспектора объектов и т.д.), так и в стиле, максимально приближенном к MS Visual Studio, когда все окна пристыковываются к центральному, в котором можно заниматься дизайном формы или редактированием кода.
Для того, чтобы привести окна редактирования и палитры компонентов к привычному виду, поэкспериментируйте с настройками Tools | Environment Options | Delphi Options | VCL Designer | Embedded designer и Tools | Environment Options | Tool Pallete.
В Delphi2005 изменилась справочная система. Изменился не только внешний вид, но внутренняя структура предлагаемой информации.
На мой взгляд, пользоваться справкой стало намного удобнее.
Показать скриншот в отдельном окне
Появилась возможность настраивать цвета для Object Inspector, смотритеTools | Environment Options | Object Inspector.
[ К содержанию ]
Редактор кода
С редактором кода стало работать намного удобнее.
Комментирование блока текста
Начнем с одной приятной мелочи. Не знаю, как кому, но мне ее иногда очень не хватало в Delphi. Я имею в виду возможность быстро закомментировать или раскомментировать блок текста в редакторе.
В новой IDE это делается легким движением руки. Выделяем текст, нажимаем клавиши [Ctrl+/] и весь выделенный код оказался закомментирован. Обратная операция делается точно так же. На всякий случай напомню, почему это лучше, чем обычные скобки {} в начале и конце куска кода. В случае использования в начале каждой строки двойного слеша нет никакой нужды заботиться о вложенных комментариях, которые могут уже быть в выделенном тексте. Этот способ "устранения" части кода бывает удобен при отладке.
Очень удобна новая возможность редактора показывать соответствующие пары скобок (см. рисунок).
[ К содержанию ]
Сворачивание части кода
Как и в Delphi8, в редакторе Delphi2005 реализовано частичное скрытие (сворачивание кода). Это позволяет работать с большими текстами, не прокручивая многостраничный экран. Достаточно оставить развернутым сейчас только тот код, который используется. Для того чтобы свернуть или развернуть нужный блок, специально предусмотрены значки [-] и [+] в левой части редактора. Если нажать на значок [-], например, возле определения метода, код этого метода будет свернут, то есть, убран из видимости. Но, кроме этого, есть возможность применить эту операцию ко всему коду, а не только к текущему месту.
В меню по правой кнопке мыши есть два пункта Fold и UnFold. Это, соответственно, операции "свернуть" и "развернуть". Для каждой из них нужно указать место действия. Например, свернуть все методы в коде или все определения типов. Хочется заметить, что "свернутая" часть кода никуда не девается, а лишь уходит из видимой части редактора. Так что, если при компиляции или во время работы "Error Insight", ошибка окажется в свернутом коде, он прекрасным образом будет развернут автоматически в нужном месте. Так что никакой путаницы не возникнет.
Кроме этих возможностей, введены две директивы, которые по синтаксису аналогичны директивам компилятора, но оказывают влияние на поведение редактора, а не на генерируемый код. Это директивы $REGION и $ENDREGION. Они задают начало и конец сворачиваемого региона кода. Можно задать имя региона, в этом случае, когда регион свернут, вместо многоточия отображается имя региона (см. рис).
[ К содержанию ]
Help Insight
Если в привычном "Code Insight" показывался тип идентификатора (переменной, функции и т.д.) и модуль, в котором он определен, то "Help Insight" представляет собой всплывающее окно-подсказку, с кратким описанием этого идентификатора и дополнительными ссылками (см. рис). Достаточно подвести мышку к нужному идентификатору, чтобы получить такой "маленький help". Использовать "Help Insight" можно в комбинации с "Code Completion". Если в окне "Code Completion" выбрать определенное свойство или метод, то справа появится окно с подсказкой.
Открыть скриншот в отдельном окне
Эта возможность реализована не только для стандартных, но и для собственных классов и переменных. Использование "Help Insight" включено по умолчанию. Местонахождение в настройках: Tools->Options->Editor Options->Code Insight
[ К содержанию ]
Error Insight
В левой части экрана есть окно "Structure". Оно используется для показа визуальных компонент, лежащих на форме, переменных и констант, списка модулей, которые подключены и так далее. Но, кроме этого окно "Structure" может показывать список синтаксических ошибок, которые определяются до момента компиляции с помощью "Error Insight".
Например, самая обычная ошибка — неверно написан идентификатор или не подключен модуль, в котором он определен. Если раньше, до момента компиляции эти ошибки не отслеживались, то сейчас ошибочные имена (идентификаторов, методов и т.п.) мгновенно обращают на себя внимание, так как в редакторе кода они подчеркиваются красной волнистой линией, а в окне "Structure" появляется полный список таких ошибок (см. рис). Естественно, что, кликнув на ошибке в списке, мы сразу попадаем на нужное место в коде.
[ К содержанию ]
Sync Edit
При выделении части кода в редакторе, на левой полосе, вслед за выделяемыми строками, передвигается маленькая иконка (на рисунке она отмечена красным). Это включение режима "Sync Edit". Если нажать на эту иконку, то выделенный текст подкрасится (при цветовых настройках по умолчанию) голубым цветом и будет выделен первый в блоке идентификатор.
Открыть скриншот в отдельном окне
Суть режима "Sync Edit" в том, что он позволяет показать в выделенном тексте все повторяющиеся идентификаторы, их может оказаться несколько групп. Самая первая считается текущей.
Для текущей группы все дубли помечены рамочкой, для остальных групп просто подчеркнуты.
Переход между группами повторяющихся идентификаторов осуществляется клавишей TAB.
Если начать изменять текущий идентификатор, то вслед за ним будут синхронно изменены все его дубли в этом выделенном блоке.
Это похоже на "Рефакторинг: переименование идентификатора".
В отличие от полноценного рефакторинга, в режиме "Sync Edit" не производится никакого синтаксического анализа, а просто ищется повторяющееся имя. Его можно применять, как "быстрый рефакторинг" или использовать для поиска всех мест, где используется искомый идентификатор.
Рекомендуется использовать этот режим для небольших блоков кода, например, для функций или методов. Для всех остальных случаев рекомендуется использовать полноценный рефакторинг.
Повторное нажатие на иконку на левой полосе редактора кода, выключает "Sync Edit" и возвращает обычный режим редактирования.
[ К содержанию ]
История изменений
По мере редактирования и сохранения кода в проекте, средой автоматически ведется история этих изменений. Для каждого модуля, включенного в проект, можно просмотреть историю изменений, сравнить разные версии файлов и, если необходимо, возвратиться к любому из промежуточных изменений кода проекта. Смотрите закладку History в редакторе кода и тему "History Manager" в документации.
Открыть скриншот в отдельном окне
После даже этой небольшой работы с новой IDE, возвращение к старым версиям в свои рабочие проекты кажется откатом назад.
[ К содержанию ]
Но, есть и неприятные моменты.
Русские буквы в комментариях к коду
Поначалу неприятно удивило открытие файлов кода с комментариями в заголовке, написанными русскими буквами в кодировке Win1251. Часть таких файлов открываются, как двоичные. После небольшого исследования оказалось, что портит все маленькая буква "я" в тексте комментариев в начале модуля. Если в новой среде написать такой комментарий в начале модуля, то он редактируется нормально. Но, если его закрыть, то вновь откроется он в двоичном виде. По-видимому, проблема связана с тем, что редактор кода по первой порции фиксированного объема определяет формат файла. Встречая в этой порции букву "я" (ее код $FF), редактор некорректно определяет формат файла. При переносе текста с буквой "я" в конец файла или в середину файла большого размера, его формат определяется корректно.
Сходная ситуация обсуждалась в Подводных камнях.
Проблема с открытием таких файлов решается или удалением слов из заголовка модуля, содержащих маленькую букву "я", или замена ее на букву "Я" в верхнем регистре. Кому что нравится.
Русские буквы в названиях каталогов проекта
Проекты VCL.NET и WinForms не запускаются из-под среды, если в полном имени каталога проекта есть русские буквы. Среда сообщает "Unable to create process".
К сожалению, ссылки в окне "Help Insight" не будут работать, если у вас в названии каталогов используются русские буквы.
[ К содержанию ]
Рефакторинг
Рефакторинг "переименование символа" — при позиционировании курсора на нужном идентификаторе и выборе пункта меню Refactoring | Rename Field, среда показывает все строки, где встречается выбранный идентификатор, и предлагает выбрать новое имя. Очень удобная возможность, как тут не вспомнить Мартина Фаулера:
"Важной частью пропагандируемого мною стиля программирования является разложение сложных процедур на небольшие методы. Если делать это неправильно, то придется изрядно помучиться, выясняя, что же делают эти маленькие методы. Избежать таких мучений помогает назначение методам хороших имен. Методам следует давать имена, раскрывающие их назначение. Хороший способ для этого - представить себе, каким должен быть комментарий к методу, и преобразовать этот комментарий в имя метода. Жизнь такова, что удачное имя может не сразу придти в голову. В подобной ситуации может возникнуть соблазн бросить это занятие - в конце концов, не в имени счастье. Это вас соблазняет бес, не слушайте его. Если вы видите, что у метода плохое имя, обязательно измените его. Помните, что ваш код в первую очередь предназначен человеку, а только потом - компьютеру. Человеку нужны хорошие имена. Вспомните, сколько времени вы потратили, пытаясь что-то сделать, и насколько проще было бы, окажись у пары методов более удачные имена. Создание хороших имен - это мастерство, требующее практики; совершенствование этого мастерства - ключ к превращению в действительно искусного программиста. То же справедливо и в отношении других элементов сигнатуры метода. Если переупорядочивание параметров проясняет суть - выполните его."
Раньше для подобных действий использовался метод переименования идентификатора в месте, где он объявлен, и инкрементная компиляция до выяснения всех мест, в которых этот идентификатор использовался.
Рефакторинг "Выделение метода" оказался вторым из удобных нововведений, в выделенном методе автоматически объявляются необходимые параметры и локальные переменные. К сожалению, пока остается мечтой автоматический поиск аналогичного кода выделенного метода в других местах и замена его вызововом выделенного метода.
Рефакторинг: процесс выделения метода
После выделения метода
Остальные рефакторинги (объявить переменную, объявить поле, выделить ресурсную строку), на мой взгляд, являются не рефакторингами в классическом смысле, а удобной возможностью редактора кода вставлять необходимые объявления, не перемещаясь в раздел объявлений.
[ К содержанию ]
Unit-тестирование
"Мой опыт показывает, что создав хорошие тесты, можно значительно увеличить скорость программирования"
(с) Мартин Фаулер.
Delphi 2005 располагает встроенными средствами для организации тестирования работы отдельных модулей программы, основанными на известных open-source проектах DUnit и NUnit (.NET). Среда позволяет создать проект-оболочку для тестов и шаблоны тестирующих модулей. Рассмотрим возможности Delphi 2005 на примере тестирования простого класса, осуществляющего перевод чисел из двоичной формы в символьную по заданному основанию системы счисления и, наоборот, из символьной в двоичную.
Создадим класс, методы которого будут выполнять перевод, а основание системы счисления будет являться свойством класса.
Реализация метода ToString будет содержать ошибки, которые мы будем обнаруживать тестированием.
Первая реализация выглядит так:
unit Convertor;
interface
type
TNumericConvertor = class
private
FBase: Integer;
public
constructor Create (const ABase: Integer);
property Base: Integer read FBase;
function ToString (const Value: Integer): string;
function ToNumber (const Value: string): Integer;
end;
implementation
{ TNumericConvertor }
constructor TNumericConvertor.Create(const ABase: Integer);
begin
Assert ((ABase > 1) and (ABase <= 36), 'Illegal Base specfied');
FBase := ABase;
end;
function TNumericConvertor.ToNumber(const Value: string): Integer;
var
I, Digit: Integer;
begin
Result := 0;
for I:=1 to Length(Value) do begin
if Value[I] > '9' then
Digit := Ord(Value[I]) - Ord('A') + 10
else
Digit := Ord(Value[I]) - Ord('0');
Assert ((Digit >= 0) and (Digit < Fbase), 'Illegal character');
Result := Result * FBase + Digit;
end;
end;
function TNumericConvertor.ToString(const Value: Integer): string;
var
Rem, Quot: Integer;
begin
Assert (Value >= 0, 'Only positive numbers can be converted');
Result := '';
Quot := Value;
while Quot <> 0 do begin
Rem := Quot mod FBase;
if Rem >= 10 then
Result := Result + Char(Rem + Ord('0'))
else
Result := Result + Char(Rem + Ord('A') - 10);
Quot := Quot div Fbase;
end;
if Result = '' then
Result := '0';
end;
end.
Создадим проект-оболочку для тестов командой File|New|Other выбрав в категории Unit Tests элемент Test Project (см. рис. 1 и 1-1).
Показать скриншоты в отдельном окне: рисунок 1 и рисунок 1-1
После этого группа проектов принимает вид:
Добавим в эту оболочку первый тестирующий модуль командой File|New|Other выбрав в категории Unit Tests элемент Test Case.
Показать скриншоты в отдельном окне:
В результате этих действий в IDE открывается окно с кодом сгенерированного класса для тестирования методов выбранного класса.
unit TestConvertor;
{
Delphi DUnit Test Case
----------------------
This unit contains a skeleton test case class generated by the
Test Case Wizard.
Modify the generated code to correctly setup and call the methods
from the unit being tested.
}
interface
uses
TestFramework, Convertor;
type
// Test methods for class TNumericConvertor
TestTNumericConvertor = class(TTestCase)
strict private
FNumericConvertor: TNumericConvertor;
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestToString;
procedure TestToNumber;
end;
implementation
procedure TestTNumericConvertor.SetUp;
begin
FNumericConvertor := TNumericConvertor.Create;
end;
procedure TestTNumericConvertor.TearDown;
begin
FNumericConvertor.Free;
FNumericConvertor := nil;
end;
procedure TestTNumericConvertor.TestToString;
var
ReturnValue: string;
Value: Integer;
begin
// TODO: Setup method call parameters
ReturnValue := FNumericConvertor.ToString(Value);
// TODO: Validate method results
end;
procedure TestTNumericConvertor.TestToNumber;
var
ReturnValue: Integer;
Value: string;
begin
// TODO: Setup method call parameters
ReturnValue := FNumericConvertor.ToNumber(Value);
// TODO: Validate method results
end;
initialization
// Register any test cases with the test runner
RegisterTest(TestTNumericConvertor.Suite);
end.
В методах тестов заменяем помеченные TODO строки на код, обеспечивающий входные данные для тестируемых методов и сравнивающие результат с ожидаемым.
В методе Setup пишем код для вызова корректного конструктора
procedure TestTNumericConvertor.SetUp;
begin
FNumericConvertor := TNumericConvertor.Create (10);
end;
Метод TestToString принимает вид:
procedure TestTNumericConvertor.TestToString;
var
ReturnValue: string;
Value: Integer;
begin
Value := 10;
ReturnValue := FNumericConvertor.ToString(Value);
Assert (ReturnValue = '10', 'Expect ''10'',
receive '''+ReturnValue+'''');
end;
И последний метод - TestToNumber
procedure TestTNumericConvertor.TestToNumber;
var
ReturnValue: Integer;
Value: string;
begin
Value := '10';
ReturnValue := FNumericConvertor.ToNumber(Value);
Assert (Returnvalue = 10, 'Expect 10,
receive '+IntToStr(ReturnValue));
end;
Компилируем и запускаем тестовый проект, его окно выглядит так.
После запуска тестов видно, что один из методов исходного класса работает некорректно, так как полученный результат не соответствует ожидаемому (Ожидается '10' получен 'AB')
Показать скриншот в отдельном окне
Анализируя исходный код метода, видно, что при переводе очередного знака числа, условия then и else необходимо поменять местами:
if Rem >= 10 then
Result := Result + Char(Rem + Ord('A') - 10)
else
Result := Result + Char(Rem + Ord('0'));
Перекомпилировав проект после исправления, снова запускаем тесты.
Видно, что ошибка исправлена, но метод все работает не так, как ожидается (Ожидается '10', получено '01').
Показать скриншот в отдельном окне
Дальнейший анализ кода метода показывает, что при переводе числа в строку старшие цифры записываются после младших, исправляем эту ошибку, часть кода метода ToString теперь выглядит так:
if Rem >= 10 then
Result := Char(Rem + Ord('A') - 10) + Result
else
Result := Char(Rem + Ord('0')) + Result;
Снова компилируем тестовый проект, после запуска убеждаемся, что исправленный метод теперь работает как ожидалось, при заданных в тесте условиях.
Показать скриншот в отдельном окне
Это не окончательный показатель гарантии правильной работы методов класса, для полной проверки необходим еще ряд тестов, тем не менее, две ошибки выявлены тестами за короткое время.
Для проверки перевода чисел в другой системе счисления можно создать еще один Test Case, например, тестирующий перевод из двоичного вида в символьный и обратно в двоичной системе счисления.
unit TestConvertor1;
{
Delphi DUnit Test Case
----------------------
This unit contains a skeleton test case
class generated by the Test Case Wizard
Modify the generated code to correctly
setup and call the methods from the unit
being tested.
}
interface
uses
TestFramework, Convertor;
type
// Test methods for class TNumericConvertor
TestTNumericConvertor1 = class(TTestCase)
strict private
FNumericConvertor: TNumericConvertor;
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestToString;
procedure TestToNumber;
end;
implementation
uses
SysUtils;
procedure TestTNumericConvertor1.SetUp;
begin
FNumericConvertor := TNumericConvertor.Create(2);
end;
procedure TestTNumericConvertor1.TearDown;
begin
FNumericConvertor.Free;
FNumericConvertor := nil;
end;
procedure TestTNumericConvertor1.TestToString;
var
ReturnValue: string;
Value: Integer;
begin
Value := 11;
ReturnValue := FNumericConvertor.ToString(Value);
Assert(ReturnValue = '1011', 'Expect ''1011'',
receive '''+ReturnValue+'''');
end;
procedure TestTNumericConvertor1.TestToNumber;
var
ReturnValue: Integer;
Value: string;
begin
Value := '1011';
ReturnValue := FNumericConvertor.ToNumber(Value);
Assert(ReturnValue = 11, 'Expect 11,
receive '+IntToStr(ReturnValue));
end;
initialization
// Register any test cases with the test runner
RegisterTest(TestTNumericConvertor1.Suite);
end.
После компиляции и запуска тестового проекта, видно, что новые тесты добавились к старым, так что любые исправления исходного кода можно протестировать как всеми созданными тестами, так и выбрав конкретные тесты.
Показать скриншот в отдельном окне
В заключение хочется добавить, что использовать unit-тесты можно было и раньше. Например, полтора года назад, одним из авторов обзора была разработана среда подобного рода для того, чтобы полностью осознать, что же такое unit-тесты. Среда включала в себя главную программу и эксперт для генерации тестирующих модулей. Разумеется, не с таким красивым и удобным интерфейсом, гораздо больше кода приходилось писать вручную, но главный итог такой разработки и использования — осознание необходимости тестирования, в особенности, использования unit-тестов как значительного подспорья для разработки программ.
Спасибо фирме Borland, что такие нужны и удобные средства уже встроены в их новый продукт — Delphi 2005.
[ К содержанию ]
Компилятор
Предопределенный символ для идентификации компилятора - VER170 (выяснено опытным путем, в Help информация отсутствует).
Многие из перечисленных ниже возможностей являются нововведениями только для компилятора Win32.
for..in..do
В язык Delphi добавлена конструкция for..in..do для перебора всех членов массива, строки, множества или коллекции.
- for Element in ArrayExpr do Stmt;
- for Element in StringExpr do Stmt;
- for Element in SetExpr do Stmt;
- for Element in CollectionExpr do Stmt;
То есть, в цикле перебираются все элементы некоего множества и для каждого выполняется тело цикла. Например, теперь ничего не стоит перевернуть строку наоборот (см. рис)
Полная и весьма понятная информация находится в справке, смотрите раздел "Declarations and Statements"
Наиболее интересным применением циклов такого вида является их использование с коллекциями для перебора элементов. Для того, чтобы класс можно было использовать с циклами for..in, класс должен реализовать предопределенный паттерн коллекции. А именно, класс должен удовлетворять следующим требованиям:
- содержать public метод экземпляра с именем GetEnumerator, который должен возвращать экземпляр класса, ссылку на интерфейс или запись (record).
- экземпляр класса, ссылка на интерфейс или запись, возвращенные методом GetEnumerator, должны содержать public метод экземпляра с именем MoveNext, возвращающий значение типа boolean.
- экземпляр класса, ссылка на интерфейс или запись, возвращенные методом GetEnumerator должны содержать public свойство экземпляра с именем Current, тип которого должен соответствовать типу элементов контейнера.
Экземпляр, возвращенный методом GetEnumerator, автоматически разрушается после окончания цикла for..in.
Следующий пример показывает реализацию паттерна коллекции
program Project1;
{$APPTYPE CONSOLE}
type
TMyIntArray = array of Integer;
TMyEnumerator = class
Values: TMyIntArray;
Index: Integer;
public
constructor Create;
function GetCurrent: Integer;
function MoveNext: Boolean;
property Current: Integer read GetCurrent;
end;
TMyContainer = class
public
function GetEnumerator: TMyEnumerator;
end;
constructor TMyEnumerator.Create;
begin
inherited Create;
Values := TMyIntArray.Create(100, 200, 300);
Index := -1;
end;
function TMyEnumerator.MoveNext: Boolean;
begin
if Index < High(Values) then
begin
Inc(Index);
Result := True;
end
else
Result := False;
end;
function TMyEnumerator.GetCurrent: Integer;
begin
Result := Values[Index];
end;
function TMyContainer.GetEnumerator: TMyEnumerator;
begin
Result := TMyEnumerator.Create;
end;
var
MyContainer: TMyContainer;
I: Integer;
Counter: Integer;
ar: TMyIntArray;
begin
MyContainer := TMyContainer.Create;
Counter := 0;
for I in MyContainer do
Inc(Counter, I);
WriteLn('Counter = ', Counter);
end.
Поддержка синтаксиса for...in уже встроена в ряд классов VCL, например, TList, TComponent, TCollection, и т.д. - в общей сложности около 15 классов. Так, например, перечисление имен компонентов формы может выглядеть следующим образом (хотя и непривычно):
var
I: TComponent;
begin
for I in Self do
ListBox.Add (I.Name);
end;
[ К содержанию ]
Модификаторы области видимости
Для большей совместимости исходного кода с Delphi for .NET введены два новых модификатора области видимости членов класса.
strict private
Члены класса с видимостью strict private доступны только самому классу.
strict protected
Члены класса с видимостью strict protected доступны только самому классу и его непосредственным наследникам.
Отличие новых модификаторов от традиционных private и protected заключается в том, что члены с новыми модификаторами не доступны постороннему коду, находящемуся в том же модуле.
Class property
Раньше, хотя компилятор и позволял использовать методы класса в качестве аксессоров свойств, обращение к таким свойствам в форме TSomeClass.PropName было невозможно. Теперь, с введением свойств класса такое обращение разрешено. Однако, в отличие от Delphi for .NET, свойства класса могут работать только через методы, т.к. понятие полей класса для компилятора Delphi for Win32 отсутствует.
type
TTestClass = class
class function GetClassProp: integer;
class procedure SetClassProp(value: integer);
class property ClassProp: integer read
GetClassProp write SetClassProp;
end;
TestClass.ClassProp := ...;
[ К содержанию ]
Вложенные типы данных и константы
Эта возможность также является новшеством только для компилятора Delphi for Win32. Теперь, как и в случае с Delphi for .NET, можно объявлять типы данных и константы внутри других классов.
type
TOuterClass = class
public
const
x = 12;
i: integer = 1;
type
TInnerClass = class
public
myInnerField: Integer;
procedure innerProc;
end;
procedure outerProc;
end;
Обращение ко вложенным типам и константам производится через имя типа, в который они вложены, например, TOuterClass.TInnerClass или TOuterClass.x. Для вложенных типов и констант действуют те же модификаторы видимости, что и для остальных членов классов.
Существует одна интересная особенность. Хотя компилятор для Win32 не поддерживает полей класса, их в какой-то мере можно заменить вложенными типизированными константами при условии, что включена опция компилятора $J (она же $WRITEABLECONST).
[ К содержанию ]
Ненаследуемые классы
Если по каким-то причинам разработчик хочет запретить создание наследников класса, это можно сделать используя модификатор sealed.
type
TMyFinalClass = class sealed(TObject)
end;
Так же, в язык добавлено ключевое слово final для вирутальных и динамических методов, запрещающее их дальнейшее перекрытие. Эта возможность присутствует как в компиляторе .NET, так и в компиляторе для Win32
Например, компиляция кода
type
TClass1 = class
private
....
public
constructor Create;
destructor Destroy; override; final;
....
end;
TClass2 = class(TClass1)
....
public
destructor Destroy; override;
end;
приведет к ошибке - E2352 Cannot override a final method.
[ К содержанию ]
XML Documentation
Для компилятора Delphi for .NET эта возможность существует с версии Delphi 8. Теперь эта возможность доступна и в компиляторе для Win32. Компилятор умеет различать в исходном тексте специальным образом оформленные комментарии и генерировать на их основе XML файлы. Формат комментариев во многом похож на XML. Каждый комментарий, который будет анализироваться на наличие тегов XML документации предшествовует документируемому объекту и должен начинаться с комбинации из трёх символов "/". Существует набор тегов, которые рекомендуется применять при оформлении комментариев. Он описан в справке .NET SDK. К сожалению для тех, кто не любит писать всякие теги руками, IDE никак не облегчает оформление таких комментариев.
Примитивный пример оформления документации:
type
///<summary> Test comment
///</summary>
TForm3 = class(TForm)
private
{ Private declarations }
///<summary> Test comment 1
///</summary>
procedure Test;
public
{ Public declarations }
end;
Примерный вид XML документации, генерируемой компилятором:
<?xml version="1.0" encoding="utf-8"?>
<namespace name="Unit3">
<class name="TForm3">
<devnotes>
<summary> Test comment
</summary>
</devnotes>
<ancestor name="TForm" namespace="Forms">
<methodref name="ArrangeIcons" visibility="public" />
<methodref name="Cascade" visibility="public" />
здесь перечисляются предки и все их члены
</ancestor>
<members>
<procedure name="Test" visibility="private">
<devnotes>
<summary> Test comment 1
</summary>
</devnotes>
</procedure>
</members>
</class>
<variable name="Form3" type="TForm3" />
</namespace>
[ К содержанию ]
Inline
В новой версии компилятора Delphi появилась возможность использования inline кода. Для этого наполнена новым смыслом директива inline. Теперь, если процедура или функция имеют директиву inline, это заставит компилятор попытаться вставить в место, где эта процедура используется, не вызов, а код тела процедуры. Само наличие директивы inline ещё не гарантирует того, что попытка будет удачной. Существуют определенные ограничения. Согласно справочной системе, эти ограничения таковы:
- inline не работает для любых видов методов позднего связывания (virtual, dynamic, message)
- inline не работает для процедур содержащих код на языке ассемблера,
- inline не работает для конструкторов и деструкторов
- inline не работает для главного блока программы и секций инициализации и финализации модулей
- inline код может быть использован внутри пакетов, но inline не работает через границы пакетов
- inline не работает в модулях, связанных кольцевой зависимостью. Это ограничение включает и неявные кольцевые ссылки между модулями. Например, если модуль A использует модуль B, модуль B использует C, а C, в свою очередь, использует A, то при компиляции модуля A не будет производиться inline-подстановка кода из модулей B и C.
- inline-подстановка в модулях, входящих в кольцевые зависимости, может быть произведена, если подстановка производится из модуля, не входящего в кольцо зависимостей. Например, если в предыдущем примере модуль A использует также модуль D, то в модуле A возможна inline-подстановка кода из модуля D.
- inline не работает, если процедура объявлена в секции interface модуля и обращается к символам, объявленным в секции implementation.
- inline не работает для методов в классах, если они обращаются к членам классов, имеющим более низкую видимость, чем сам метод. Например, если public метод обращается к private методу, то для такого метода inline-подстановка осуществляться не будет.
- если процедура, помеченная как inline использует процедуры или переменные из внешних модулей, то все эти модули должны быть перечислены в списке uses того модуля, где inline процедура будет использована, иначе inline-подстановка не производится.
- inline-подстановка не осуществляется для процедур и функций, которые используются в выражениях проверки условия циклов while и repeat.
При использовании inline процедур следует помнить о том, что изменение кода такой процедуры приведет к перекомпиляции всех модулей, где она используется.
Также для контроля использования inline-подстановок введена директива компилятора {$INLINE}. Она может принимать следующие значения:
- {$INLINE ON} - Процедуры, с директивой inline будут помечены, как процедуры, для которых возможна inline-подстановка. При вызове таких процедур будет сделана попытка inline подстановки кода. Действует по умолчанию.
- {$INLINE AUTO} - Процедуры, с директивой inline будут помечены, как процедуры, для которых возможна inline-подстановка только в том случае, если код процедуры будет размером меньше 32 байт.
- {$INLINE OFF} - Процедуры, не смотря на наличие директивы inline, никогда не будут помечены, как процедуры, для которых возможна inline-подстановка. При вызове процедур попытка inline подстановки кода не будет сделана.
Unsafe Code
Для компилятора Delphi for .NET добавлена возможность включения небезопасного кода в приложения .NET. Для этого введена локальная директива компилятора {$UNSAFECODE}, которая может принимать значения ON и OFF а также добавлено ключевое слово unsafe, которое применяется к процедурам и функциям. Приложения, использующие небезопасный код не проходит проверку при помощи утилиты PEVerify. Подробнее о небезопасном коде смотрите в документации .NET SDK.
procedure unsafeProc; unsafe;
begin
end;
[ К содержанию ]
Unicode-идентификаторы
Появилась возможность использовать в именах типов и переменных символы Unicode.
Запись вида
type
Работник = record
Фамилия: string;
Имя: string;
Отчество: string;
ДатаРождения: TdateTime;
Должность: string;
end;
выглядит понятнее, чем
Rabotnik = record
Familija: string;
Imya: string;
Ochestvo: string;
DataRogdenija: TdateTime;
Dolgjnost: string;
end;
Разумеется, такой код будет многим непривычен и вызовет недовольные нарекания в духе "настоящий программист должен писать имена переменных/типов/методов на английском языке", но давайте помнить, что программа пишется в первую очередь для человека, компилятору абсолютно все равно, какие имена будут объявлены в программе.
Пример компилирующегося и работающего кода:
type
Целое = Integer;
procedure TfMain.BtnCountClick(Sender: TObject);
var
Счетчик: Целое;
begin
for Счетчик:=0 to 5 do begin
btnCount.Caption := IntToStr(Счетчик);
Sleep(500);
Application.ProcessMessages;
end;
end;
[ К содержанию ]
Расширенный синтаксис объявления и инициализации массивов
Delphi для Win32
Теперь можно делать задание размеров массива и инициализацию одной строкой
type
TMyIntArray = array of Integer;
var
Ints: TMyIntArray;
begin
Ints := TMyIntArray.Create(1,2,3,4,5);
Delphi for .NET
Новый расширенный синтаксис позволяет объявлять массивы в форме
array[, ..., ] of baseType;
Также возможна инициализация массивов при помощи стандартной процедуры new.
var
a: array [,,] of integer; // 3 dimensional array
b: array [,] of integer; // 2 dimensional array
c: array [,] of TPoint; // 2 dimensional array of TPoint
begin
// New taking element type and size of each dimension.
a := New(array[3,5,7] of integer);
// New taking the element type and initializer list.
b := New(array[,] of integer, ((1,2,3), (4,5,6)));
// New taking an initializer list of TPoint.
c := New(array[,] of TPoint, (((X:1;Y:2), (X:3;Y:4)),
((X:5;Y:6), (X:7;Y:8))));
end.
[ К содержанию ]
Отладка
Понравилось поведение системы при возникновении Exception — появляется окно с уведомлением об Exception и с возможностью поставить галочку "Игнорировать этот тип Exception", вместо того, чтобы открывать окно Tools | Debugger..
Изменилась работа с точками останова. Появилась очень удобная возможность, не удаляя точку останова, отключить ее, пометив как "disable". Это можно сделать в редакторе кода по правой кнопке на точке останова, и прямо в списке "Breakpoint list". В этом списке можно включать/выключать все точки или определенные группы (меню по правой кнопке). Так же, теперь прямо в окне "Breakpoint list" можно изменять значение Condition и принадлежность к определенной группе для каждой точки.
[ К содержанию ]
Встроенный Data Explorer
В IDE интегрирован Data Explorer, который содержит как средства просмотра базы данных, так и ряд инструментов для редактирования. Окно Data Explorer можно найти на одной из закладок окна Project Manager справа от редактора кода (при умолчанных настройках среды) или в меню View | Data Explorer
Выбираете провайдера для вашей БД, настраиваете коннекцию к базе и получаете список ее объектов:
[ К содержанию ]
Таблицы
Для таблиц определены следующие операции:
Просмотр данных
Это операция по умолчанию — двойной клик по имени таблицы в списке. Открывается отдельное окно с содержимым таблицы. Возможно редактировать все поля, даже identity и computed column. Диагностика производится в момент сохранения изменений (правая кнопка мыши | Update/Rollback), так что испортить таблицу затруднительно.
Изменение структуры
Визуальный аналог команды "Alter table".
В этом окне по правой кнопке мыши доступны команды Save changes/Show DDL/ Exeсute DDL
DDL (Data definition language) — текст SQL-скрипта, который отражает сделанные визуально изменения в структуре таблицы.
Удаление таблицы
Выполнение команды "Drop table"
Копирование таблицы
Копирование существующей таблицы в новую. Происходит, как создание новой таблицы с такой же структурой (имя новой таблицы запрашивается при выполнении paste) и заполнении ее данным из копируемой таблицы.
[ К содержанию ]
Хранимые процедуры
Доступные операции Refresh/View Parameters. Окно просмотра параметров открывается при двойном клике на имени процедуры. В этом окне можно указать значения всех входных параметров и, выполнив процедуру, получить заполненные значениями выходные параметры (см. рис). Для выполнения процедуры можно воспользоваться иконкой в верхнем левом углу окна или по правой кнопке мыши (команда Execute).
Если хранимая процедура в качестве результата возвращает еще и (или только) набор данных, необходимо
поставить галочку "Stored procedure has one or more cursors" и выполнить процедуру снова.
Просмотр скриншотов в отдельном окне:
Окно просмотра параметров
Окно с настройкой параметров процедуры и получением результатов
Результат работы хранимой процедуры, которая возвращает набор данных
Безусловно, новые возможности для тестирования работы хранимых процедур очень удобны и позволят упростить жизнь разработчика баз данных.
В качестве недостатка можно отметить отсутствие возможности прервать выполнение хранимой процедуры, если время выполнения оказывается довольно продолжительным.
[ К содержанию ]
SQL Window
Это привычное окно для выполнения SQL-запросов. Так как тестирование проходило только для MS SQL Server, то возможно, некоторые странности связаны с конкретным драйвером.
Сами SQL-запросы любой сложности (UNION, вложенные подзапросы и т.п.) выполняются без проблем. Странности начались после попытки исполнить в этом окне процедуру ("execute имя_процедуры"), которая в качестве результата возвращает набор данных. В качестве результата было получено сообщение "-1 row(s) affected". И этот результат был одинаков для всех процедур одного сервера. Тест на другом сервере дал иной результат, возможно этот эффект зависит от настроек на сервере (или от настроек конкретной базы), но такого иследования не проводилось. Итак, на другом сервере после выполнения процедуры было получено окошко с сообщением, например, таким: "192 row(s) affected", что само по себе верно, но никакого результата, то есть набора данных, все равно не было выведено. Если в тексте процедуры был оператор "Insert Into имя_таблицы exec имя_процедуры", то в качестве nколичества обработанных строк в результирующем сообщении выдавалось количество строк этого insert'а, а вовсе не nпоследнего select'а процедуры.
Можно предположить, что проблема кроется в ADO.NET, на котором реализован Data Explorer.
И, все же, несмотря на это, Data Explorer добавляет в среду разработки функционал, который реально может
облегчить жизнь разработчику клиентских приложений для баз данных.
* * *
Данный обзор составлен по результатам первого знакомства с новой средой разработки. Изучить все нововведения в Delphi2005 за короткий срок невозможно, но такой задачи мы и не ставили перед собой. Разделив работу на параллельные части, мы постарались охватить как можно больше интересных, с нашей точки зрения, нововведений и "вкусностей" нашей любимой среды разработки.
Спасибо компании Borland за возможность ознакомиться с новой версией, которая несомненно, позволит вывести разработку приложений на качественно новый этап.
К материалу прилагаются файлы:
Пример для раздела "Unit-тестирование" (565.5 K)