有关在Delphi中使用嵌套"With"语句的任何资源/教程吗?

Gar*_*cks 6 delphi with-statement

我正在尝试正确使用delphi中的语句.

总的来说,做简单的事情似乎相当简单,但我有兴趣找到一些关于使用嵌套语句的好的代码示例和/或教程.例如

with object1, object2, etc... do 
  begin
  statements
  end;
Run Code Online (Sandbox Code Playgroud)

我不确定的是以这种方式使用语句时的优先顺序.

任何建议表示赞赏.

Nic*_*ges 20

我能给你的最好建议是:

不要永远使用.

如果你想使用'with',那就去躺下,直到感觉过去.

如果你想使用嵌套,用锤子敲击你的手直到欲望消失.

'with'只是一个等待发生的错误.更改使用它的类可以改变代码的含义.它创建了不精确的语义,这总是很糟糕.

保存击键绝不是使用'with'的好理由.现在再进行一些击键可以为您节省很多痛苦.

'应该'应该避开.

  • @The_Fox关于Verity Stob的最后一句话:http://www.theregister.co.uk/2012/01/16/verity_stob_sons_of_khan_2011/print.html (5认同)
  • 我基本上同意这个建议,尽管我可能倾向于不那么教条.我认为可以根据自己的优点判断每个候选人使用"with",从而避免教条,并且仍然发现判断出来反对使用`with`!遗憾的是你没有解决主要的问题,尽管哪个涉及可怕的嵌套`with`的优先级.现在,拒绝嵌套的`with`可能是我接受的规则,我觉得需要使用dogma这个词!;-) (5认同)
  • 只要有关于替代方法的指导,我对教条式编程规则没有任何问题.不幸的是,我看到很多以"永远不会......"开头的例子似乎很少以"......这就是你应该怎么做......"的字眼结束.当然,"with"的替代方法是声明局部变量,将局部变量的值赋给long-winded-object-name,然后调用局部变量上的方法.例如var tbl:TDataset; tbl:= tblMyReallyLongNamedTable; tbl.first; 而不是tbl.eof; 等等 (5认同)
  • FreeAndNil怎么样?:) (4认同)
  • (我将在这里发挥异端角色)Delphi的`with`需要修改它的语法.最好的起点(arggggghhhh)是Vb.Net`with`.所有商品都没有Delphi`with`的问题. (2认同)
  • 我曾经被'with'咬过一次 - 再也没有了.在一个复杂的构造函数中,似乎我的代码无法简单地递增一个整数.通过在一个小组上发布我的问题经过几个小时的摆弄和尴尬,10张左右的海报回复'!'.果然,一些不起眼的属性与我的整数同名...... (2认同)

OnT*_*Fly 7

在线参考的摘录指出:

当with之后出现多个对象或记录时,整个语句被视为一系列嵌套的语句.从而:

with obj1, obj2, ..., objn do statement
Run Code Online (Sandbox Code Playgroud)

相当于:

 with obj1 do
  with obj2 do
    ...
    with objn do
      // statement
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果可能,语句中的每个变量引用或方法名称都将被解释为objn; 否则,如果可能,将其解释为objn1; 等等.该规则同样适用于解释OBJ文件本身,所以,举例来说,如果objn是两者的成员obj1obj2,它被解释为obj2.objn.

  • 同时,由于对代码可读性和调试不便的影响,过度使用`with`(有时**使用'with`甚至**)不赞成. (14认同)

NGL*_*GLN 7

既然有足够的意见,我会尽力回答你的问题,虽然这个前面的答案很好地回答了你问题的语法部分.它对文档的引用解释了优先顺序,以及其他有趣的规则.将其视为强制性阅读.

正如您可能已经理解的那样,(一个未经证实的)唯一的问题with是,您可以Self使用相同的名称来寻址(或者来自一个嵌套级别的实例)的成员,而不是寻址特定的实例成员.显然不打算:

procedure TForm1.SomeRoutine;
var
  Button: TControl;
begin
  Button := Button1;
  with Button do
    Caption := 'Press here';
end;
Run Code Online (Sandbox Code Playgroud)

运行,并惊讶于表单的标题已更改.当然,TControl声明一个Caption属性,但是那个属性是受保护的,因此Caption在此代码中引用了该形式的属性.但是下一个示例也不保证设置按钮的标题:

procedure TForm1.SomeRoutine;
begin
  with Button1 do
    Caption := 'Press here';
end;
Run Code Online (Sandbox Code Playgroud)

......因为也许Button1被声明为其中一些异国情调的按钮类型一个标题,但物业的名称可能是Title,BeschriftungLegende.

这些是简单的例子,很容易修复,几乎不需要调试.但是考虑内存中记录和对象的非可视成员:这些错误很难调试,因为:在哪里看?当然,运气不错,Self没有这样的成员,以防编译器发出警告:

procedure TForm1.SomeRoutine;
begin
  with Button1 do
    Cpation := 'Press here';
end;
Run Code Online (Sandbox Code Playgroud)

...但不要指望只会产生编译器捕获的错误.

这种错误容易实现.由我,由您和任何其他(经验丰富的)开发人员.特别是当您处理或使用正在构建或正在重构的代码时.很明显,对于嵌套的withs,这些错误的调试问题正在堆积成指数级别.

现在,与我们这里的其他人不同,我with经常使用,但仅限于固定库类型,其成员永远不会被重命名.例如:TRect, TPoint, TMessage, TGridRect, TControl, TCanvas,etc ...就是几乎所有的RTL记录类型以及一些VCL类,但几乎从不在我自己的库类型上.如果你真的不想使用with,我建议如下:


编辑:

我已成为无营地的成员.

我上面的例子假设with只有向上的危险,比如混合Child.Caption和Self.Caption.但是最近,当将一些代码从D7移植到XE2时,我在向下方向遇到了麻烦.实际上,使用上面的"安全示例",当然:

  with GripRect[I] do
  begin
    ...
    Left := Width - W[I];
Run Code Online (Sandbox Code Playgroud)

打算Width成为Self,但由于XE2 TRect也有Width成员,我不得不重写代码:

    Left := Self.Width - W[I];
Run Code Online (Sandbox Code Playgroud)

结论:确实没有安全的用法with.

  • 哇,昨晚我梦到这个答案得到了800次投票...;) (3认同)