Код
with TClipper.Create do
try
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
finally
free;
end
является сокращением для
with TClipper.Create do
begin
try
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
finally
free;
end;
end;
TClipper.Create
, создает объект типа TClipper
и возвращает его, а также оператор with
, которыйработает как в большинстве языков, позволяет получить доступ к методам и свойствам этого объекта TClipper без использования синтаксиса NameOfObject.MethodOrProperty
.
(Более простой пример:
MyPoint.X := 0;
MyPoint.Y := 0;
MyPoint.Z := 0;
MyPoint.IsSet := true;
можно упростить до
with MyPoint do
begin
X := 0;
Y := 0;
Z := 0;
IsSet := true;
end;
)
Но в вашем случае вам никогда не нужно объявлять объект TClipper как переменную, потому что вы создаете его и можете обращаться к его методам и свойствам с помощью with
construct.
Таким образом, ваш код почти эквивалентен
var
Clipper: TClipper;
Clipper := TClipper.Create;
Clipper.AddPolygon(subject, ptSubject);
Clipper.AddPolygon(clip, ptClip);
Clipper.Execute(ctIntersection, solution);
Clipper.Free;
Первая строка, Clipper := TClipper.Create
, создает объект TClipper
.Следующие три строки работают с этим объектом, а затем Clipper.Free
уничтожает объект, освобождая ОЗУ и, возможно, также процессорное время и ресурсы ОС, используемые объектом TClipper
.
Но приведенный выше код не годитсяпотому что, если происходит ошибка (создается исключение) в пределах AddPolygon
или Execute
, то Clipper.Free
никогда не будет вызываться, и поэтому у вас есть утечка памяти.Чтобы предотвратить это, Delphi использует конструкцию try...finally...end
:
Clipper := TClipper.Create;
try
Clipper.AddPolygon(subject, ptSubject);
Clipper.AddPolygon(clip, ptClip);
Clipper.Execute(ctIntersection, solution);
finally
Clipper.Free;
end;
Код между finally
и end
гарантированно будет выполняться, даже если создается исключение и даже если вы вызываете Exit
, между try
и finally
.
Что означает Мейсон, так это то, что иногда конструкция with
может быть краской в ... мозгу из-за конфликтов идентификаторов.Например, рассмотрим
MyObject.Caption := 'My test';
Если вы напишите это внутри конструкции with
, т.е. если вы напишите
with MyObect do
begin
// A lot of code
Caption := 'My test';
// A lot of code
end;
, вы можете запутаться.Действительно, чаще всего Caption :=
меняет заголовок текущей формы, но теперь, благодаря выражению with
, вместо этого будет меняться заголовок MyObject.
Еще хуже, если
MyObject.Title := 'My test';
и MyObject не имеет свойства Caption
, и вы об этом забываете (и думаете, что свойство называется Caption
), тогда
MyObject.Caption := 'My test';
даже не скомпилируется, тогда как
with MyObect do
begin
// A lot of code
Caption := 'My test';
// A lot of code
end;
скомпилируется просто отлично, но не сработает так, как вы ожидаете.
Кроме того, такие конструкции, как
with MyObj1, MyObj2, ..., MyObjN do
или вложенные with
операторы, как в
with MyConverter do
with MyOptionsDialog do
with MyConverterExtension do
..
может привести к множеству конфликтов.
В защиту заявления With
Я заметил, что почти есть консенсус (по крайней мере, в этой теме), чтоwith
утверждение скорее зло, чем добро.Хотя я осознаю потенциальную путаницу и влюбился в нее пару раз, я не могу согласиться.Тщательное использование оператора with
может сделать код более красивым.И это уменьшает риск путаницы из-за "штрих-кода" .
Например:
Сравните
var
verdata: TVerInfo;
verdata := GetFileVerNumbers(FileName);
result := IntToStr(verdata.vMajor) + '.' + IntToStr(verdata.vMinor) + '.' + IntToStr(verdata.vRelease) + '.' + IntToStr(verdata.vBuild);
с
with GetFileVerNumbers(FileName) do
result := IntToStr(vMajor) + '.' + IntToStr(vMinor) + '.' + IntToStr(vRelease) + '.' + IntToStr(vBuild);
Нет абсолютно никакого риска путаницы, и мы не только сохраняем временную переменную в последнем случае - она также гораздо более читаема.
Или как насчет этого очень, очень стандартного кода:
with TAboutDlg.Create(self) do
try
ShowModal;
finally
Free;
end;
Где именно риск путаницы?Из моего собственного кода я мог бы привести сотни других примеров операторов with
, которые все упрощают код.
Кроме того, как уже было сказано выше, риск использования with
вообще отсутствует, посколькуты знаешь что делаешьНо что, если вы хотите использовать оператор with
вместе с MyObject
в приведенном выше примере: тогда внутри оператора with
Caption
равен MyObject.Caption
.Как вы измените заголовок формы?Простой!
with MyObject do
begin
Caption := 'This is the caption of MyObject.';
Self.Caption := 'This is the caption of Form1 (say).';
end;
Еще одно место, где может быть полезно с, - это работа со свойством или результатом функции, выполнение которого занимает не тривиальное время.
Работа с TClipperПример выше, предположим, что у вас есть список объектов TClipper с slow методом, который возвращает ограничитель для определенного TabSheet.
В идеале вы должны вызывать этот метод только один раз, так что вы можетеиспользовать явную локальную переменную или неявную, используя с .
var
Clipper : TClipper;
begin
Clipper := ClipList.GetClipperForTab(TabSheet);
Clipper.AddPolygon(subject, ptSubject);
Clipper.AddPolygon(clip, ptClip);
Clipper.Execute(ctIntersection, solution);
end;
ИЛИ
begin
with ClipList.GetClipperForTab(TabSheet)do
begin
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
end;
end;
В подобном случае подходит любой из этих методов, но в некоторых случаях, как правило, в сложных условных выражениях a может быть более понятным.
var
Clipper : TClipper;
begin
Clipper := ClipList.GetClipperForTab(TabSheet);
if (Clipper.X = 0) and (Clipper.Height = 0) and .... then
Clipper.AddPolygon(subject, ptSubject);
end;
ИЛИ
begin
with ClipList.GetClipperForTab(TabSheet) do
if (X = 0) and (Height = 0) and .... then
AddPolygon(subject, ptSubject);
end;
В конце концов, это вопрос личного вкуса.Обычно я использую с только с очень узким прицелом и никогда не вкладываю их.Используемые таким образом они являются полезным инструментом для уменьшения штрих-кода .