我找到了以下代码段here:
with TClipper.Create do
try
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
finally
free;
end
好奇,free
语句/功能(finally
和end
之间)在这里做了什么?谷歌没有帮助。
答案 0 :(得分:23)
代码
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
构造访问其方法和属性。
所以你的代码几乎等于
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
销毁该对象,释放RAM,还可能释放TClipper
对象使用的CPU时间和操作系统资源。
但是上面的代码并不好,因为如果在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
和{{1之间调用try
也是如此}}
Mason的意思是,由于标识符冲突,有时finally
构造可能是......大脑中的一个绘画。例如,考虑
with
如果你在MyObject.Caption := 'My test';
结构中写下这个,即你写的是
with
那么你可能会感到困惑。实际上,通常with MyObect do
begin
// A lot of code
Caption := 'My test';
// A lot of code
end;
更改当前表单的标题,但现在,由于Caption :=
语句,它将改变MyObject的标题。
更糟糕的是,如果
with
并且MyObject没有MyObject.Title := 'My test';
属性,你忘记了这一点(并认为该属性被称为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
语句可以使代码看起来更漂亮。这减少了"barfcode"导致混淆的风险。
例如:
比较
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
另一个可能有用的地方是使用属性或函数结果时需要花费很多时间来执行。
要使用上面的TClipper示例,假设您有一个带有 slow 方法的TClipper对象列表,该方法返回特定TabSheet的限幅器。
理想情况下,您应该只调用此getter一次,因此您可以使用显式局部变量,也可以使用带的隐式变量。
with MyObject do
begin
Caption := 'This is the caption of MyObject.';
Self.Caption := 'This is the caption of Form1 (say).';
end;
或强>
var
Clipper : TClipper;
begin
Clipper := ClipList.GetClipperForTab(TabSheet);
Clipper.AddPolygon(subject, ptSubject);
Clipper.AddPolygon(clip, ptClip);
Clipper.Execute(ctIntersection, solution);
end;
在这样的情况下,任何一种方法都可以,但在某些情况下,通常在复杂的条件下,a可以更清晰。
begin
with ClipList.GetClipperForTab(TabSheet)do
begin
AddPolygon(subject, ptSubject);
AddPolygon(clip, ptClip);
Execute(ctIntersection, solution);
end;
end;
或强>
var
Clipper : TClipper;
begin
Clipper := ClipList.GetClipperForTab(TabSheet);
if (Clipper.X = 0) and (Clipper.Height = 0) and .... then
Clipper.AddPolygon(subject, ptSubject);
end;
最终是个人品味的问题。我通常只使用带有的,范围非常窄,并且永远不会嵌套它们。以这种方式使用它们是减少 barfcode 的有用工具。
答案 1 :(得分:15)
这是对TObject.Free的调用,基本上定义为:
if self <> nil then
self.Destroy;
它正在with
语句中创建的未命名TClipper对象上执行。
这是您不应该使用with
的一个很好的例子。它往往会使代码难以阅读。
答案 2 :(得分:7)
Free调用对象的析构函数,释放对象实例占用的内存。
答案 3 :(得分:3)
我对Delphi一无所知,但我认为它正在释放TClipper使用的资源,就像C#中的using语句一样。这只是猜测......
答案 4 :(得分:0)
任何dinamicly创建的对象必须在使用后调用 free 释放对象创建的alocated内存。 TClipper对象是桌面内容创建,捕获和管理工具。所以它是某种带有Clipper的Delphi连接对象。 创建(对象创建)在尝试finaly end; 语句中处理是什么意思,如果与Clipper的连接不成功,则不会创建对象TClipper,也不能在尝试最后结束之后释放; 声明。
答案 5 :(得分:0)
如果“有”像某些海报所暗示的那样邪恶,他们可以解释一下
1.为什么Borland创造了这种语言结构,和
2.为什么他们(Borland / Embarcadero / CodeGear)在他们自己的代码中广泛使用它?
虽然我当然明白一些Delphi程序员不喜欢“with”,虽然承认有些用户滥用它,但我认为说“你不应该使用它”是愚蠢的。
angusj - 违规代码的作者:)