我正在尝试正确使用delphi中的语句。
总的来说,做简单的事情看起来相当简单,但我有兴趣找到一些关于使用嵌套语句的好的代码示例和/或教程。 E.G。
with object1, object2, etc... do
begin
statements
end;
我不确定的是以这种方式使用语句时的优先顺序。
感谢任何建议。
答案 0 :(得分:20)
我能给你的最好建议是:
不要永远使用。
如果你想使用'with',那就去躺下,直到感觉过去。
如果您想使用嵌套,请用锤子敲击您的手,直到欲望消失为止。
'with'只是一个等待发生的错误。更改使用它的类可以改变代码的含义。它创建了不精确的语义,这总是很糟糕。
保存击键绝不是使用'with'的好理由。现在再进行一些击键可以为您节省很多痛苦。
'有'应该避开。
答案 1 :(得分:7)
来自online reference州的摘录:
当多个对象或记录出现后,整个 语句被视为一系列嵌套的语句。因此:
with obj1, obj2, ..., objn do statement
相当于:
with obj1 do with obj2 do ... with objn do // statement
在这种情况下,语句中的每个变量引用或方法名称都是 如果可能,解释为
objn
的成员;否则就是 如果可能,解释为objn1
的成员;等等。相同 规则适用于解释objs本身,因此,为 例如,如果objn
是obj1
和obj2
的成员,则会对其进行解释 为obj2.objn
。
答案 2 :(得分:7)
既然已经有足够的意见,我会尝试完全回答你的问题,尽管this previous answer已经很好地回答了你问题的语法部分。它对documentation的引用解释了优先顺序,以及其他有趣的规则。将其视为强制性阅读。
正如您可能已经理解的那样,(一个未通过的)with
的唯一问题是,您可能正在寻找{{1}的成员,而不是寻址特定的实例成员(或者来自一个嵌套级别的实例)具有相同的名称,您显然不打算这样做:
Self
运行,并惊讶于表单的标题已更改。当然,procedure TForm1.SomeRoutine;
var
Button: TControl;
begin
Button := Button1;
with Button do
Caption := 'Press here';
end;
声明了TControl
属性,但该属性受到保护,因此此代码中的Caption
指的是表单的Caption
。但是下一个例子也不能保证设置按钮的标题:
procedure TForm1.SomeRoutine;
begin
with Button1 do
Caption := 'Press here';
end;
...因为可能Button1
被声明为具有标题的异常按钮类型,但属性名称可以是Title
,Beschriftung
,或Legende
。
这些是很容易修复的简单示例,几乎不需要调试。但是考虑内存中记录和对象的非可视成员:这些错误很难调试,因为:在哪里看?当然,运气不错,Self
没有这样的成员,以防编译器发出警告:
procedure TForm1.SomeRoutine;
begin
with Button1 do
Cpation := 'Press here';
end;
...但不要指望只会产生编译器捕获的错误。
这些错误很容易 。由我,由您和任何其他(经验丰富的)开发人员。特别是当您处理或使用正在构建或正在重构的代码时。显然,对于嵌套的with
s,这些错误导致的调试问题正在堆积成指数级别。
现在,与我们其他人不同,我经常使用with
,但仅限于“成员永远不会重命名的固定库类型。例如:TRect, TPoint, TMessage, TGridRect, TControl, TCanvas,
等... I.e.几乎所有RTL记录类型以及一些VCL类,但几乎从不在我自己的库类型上。如果你真的不想使用with
,我建议如下:
安全示例:
with ARect do
ExcludeClipRect(DC, Left, Top, Right, Bottom); //TRect will always have these
棘手的例子:
with Query, Parameters do
begin
Connection := AConnection;
ParamValues['ID'] := ID; //TParameters has a few same named members as dataset
Open;
end;
错误的例子:
with TMyLabel do
Color := clYellow; //My label may become transparent in future
我已成为无营地的成员。
上面的例子假设with
仅在向上方向存在危险,例如将Child.Caption与Self.Caption混淆。但是最近,当将一些代码从D7移植到XE2时,我在向下方向遇到了麻烦。实际上,使用上面的“安全示例”,当然可以:
with GripRect[I] do
begin
...
Left := Width - W[I];
将Width
视为Self
,但由于XE2的TRect
也有Width
成员,我必须将代码重写为:
Left := Self.Width - W[I];
结论:with
确实没有安全用法。
答案 3 :(得分:3)
Delphi的with
是有问题的 - 它是“不精确的语义”真的可以咬你的后方。
嵌套with
... OMG ......灾难等待发生。从来不需要嵌套版本
13年的德尔福。我会在接下来的几年里避免。
编辑:
在关于with
的其他讨论中,有人指出新语法会很好。一个起点
是Vb.Net with
:
With Something.Somewhere
.over.the.rainbow = True
End With
我不喜欢(有点味道),但它比Delphi好多了。我在这些讨论中看到的替代语法的建议是:
With SS:Something.Somewhere.over do
SS.the.rainbow = true;
SS.the.Storm = false;
end;
答案 4 :(得分:2)
我讨厌甚至这样说,但要弄清楚范围规则是如何运作的并不是很难。胜利的最后范围。总是
但是人类有这个问题,在心理学上称之为块理论。当你被提出七个要记住的东西时,一个就会失败,因为你的大脑有大约6个本地寄存器来保存。想象一下,简单的标识符Foo
出现在这里:
with EXPRESSION1 do begin
with EXPRESSION2 do begin
Foo;
end;
end;
上述内容适用于与with EXPRESSION1, EXPRESSION2 do begin...
相同的所有意图。
让我们看看范围之类的简单规则在一段时间后变得过于复杂。让我们假设我们在一些delphi应用程序中具有以下级别的范围:
use
子句中每个单元的单位范围。 更新 David向我指出,我应该提到的是,我们确实有5 + x范围,而不是上面的6个“范围”,其中x是{{1}的长度条款。
现在,问题不在于WITH语句不清楚,如上所述,当你有6层词汇范围时,人类很容易迷失,并要求你不仅要知道所有的地方定义了uses
,因为如果你认为最里面的With语句定义了一个名为Foo
的东西,那么你就不会在代码中找到一个相当讨厌且难以找到的bug。所以,我们有非常聪明,非常有能力的人,比如尼克,说非常明智的事情,比如“永远不要用”。我同意尼克的99%。
我也认为你可以说敌人没有,这是Delphi开发人员必须继续以“RAD风格”迭代地增加他们的应用程序,直到他们成为怪物。使用200个其他单位的单位乱七八糟,每个单位使用200个其他单位,甚至比滥用Foo
声明更容易让你感到悲伤。
WITH
不是坏代码中的全部问题,它只是Delphi开发人员发动机罩中最常见的蜜蜂。也许它比过度使用 - 条款更受关注,但在我的整个职业生涯中,依赖性 - 地狱和巨大用途 - 条款使生活变得比WITH
多100倍。所以我认为WITH
已经过度完成,其他应该考虑更多的事情正在考虑之中。
使用with的合理替代方法是使用单个字母变量名称(我知道,继续并且不同意),并避免所有范围模糊:
WITH considered harmful
许多人会说,这比这更好:
procedure NoWithPlease;
var
a:TSomething;
begin
a := Some.Long.Expression[x].That.You.Dont.Want.To.Repeat.Six.Times;
a.Foo := 'test';
a.Bar := 'test2'
end;
现在我被procedure WithPleasure;
begin
with Some.Long.Expression[x].That.You.Dont.Want.To.Repeat.Six.Times do begin
Foo := 'test';
Bar := 'test2'
end;
end;
多次叮咬,以提倡其不受限制的使用。但我也认为有时它实际上比做局部变量更好。它不要求您声明局部变量,也不需要确定表达式的类型。如果delphi有WITH
(C ++中的type inference
关键字),那么我会说,我们可以很容易地完全没有auto
,但事实上,它是一种避免的方式静态地创建对实现类型的依赖,以及创建可读子范围的能力,它有时可以使您的代码更容易阅读,有时会使其更糟,特别是当有WITH
级以上时声明。
然而,关于这个问题的意见各不相同,并且像其他编程主题一样,往往会变成自行车讨论,或更糟糕的是,一场圣战。
我建议的规则:
避免WITH
,除非它使您的代码更好。大多数你认为需要的地方,你不需要使用局部变量。
始终避免多级WITH
语句。