Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 为什么我不应该使用;加上;在德尔菲?_Delphi_With Statement - Fatal编程技术网

Delphi 为什么我不应该使用;加上;在德尔菲?

Delphi 为什么我不应该使用;加上;在德尔菲?,delphi,with-statement,Delphi,With Statement,我听过很多程序员,特别是Delphi程序员对“with”的使用不屑一顾 我认为它使程序运行得更快(只对父对象进行了一次引用),而且如果使用得当(不到十几行代码且没有嵌套),读取代码也更容易 下面是一个例子: procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32); begin with ARect do FillRectS(Left, Top, Right, Bottom, Value); end; 我喜欢将与一

我听过很多程序员,特别是Delphi程序员对“with”的使用不屑一顾

我认为它使程序运行得更快(只对父对象进行了一次引用),而且如果使用得当(不到十几行代码且没有嵌套),读取代码也更容易

下面是一个例子:

procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32);
begin
  with ARect do FillRectS(Left, Top, Right, Bottom, Value);
end;

我喜欢将
一起使用。我怎么了?

我不喜欢它,因为它会让脱布成为一件麻烦事。你不能仅仅用鼠标悬停在变量上就读取变量或类似的值。

这种争论在Javascript中也经常发生


基本上,使用语法很难一目了然地判断您调用的是哪个Left/Top/etc属性/方法。您可以使用一个名为Left的局部变量,以及一个名为Left的属性(我已经有一段时间没有使用delphi了,如果名称错误,很抱歉),甚至可能是一个名为Left的函数。任何不太熟悉ARect结构的人在阅读代码时都可能会非常迷茫。

只要保持简单并避免歧义,代码就没有问题


据我所知,它并没有加快任何速度——它只是一种纯粹的语法糖。

在这种情况下,我更喜欢VB语法,因为在这里,您需要在with块中的成员前面加一个
,以避免歧义:

With obj
    .Left = 10
    .Submit()
End With

但是实际上,一般来说,
没有什么问题。

使用with的一个烦恼是调试器无法处理它。因此,这使得调试更加困难

一个更大的问题是代码不太容易阅读。尤其是with语句稍微长一点时

procedure TMyForm.ButtonClick(...)
begin
  with OtherForm do begin
    Left := 10;
    Top := 20;
    CallThisFunction;
  end;
end;
将调用哪个窗体的CallThisFunction?自我(TMyForm)还是其他形式?如果不检查OtherForm是否有CallThisFunction方法,就无法知道

最大的问题是,你可以在不知情的情况下简化bug。如果TMyForm和OtherForm都有一个CallThisFunction,但它是私有的呢。您可能希望调用OtherForm.CallThis函数,但事实并非如此。如果不使用with,编译器会警告您,但现在它没有


在中使用多个对象会使问题成倍增加。参见

它允许不称职或邪恶的程序员编写不可读的代码。因此,只有在你既不无能也不邪恶的情况下,才可以使用此功能。

你在打字中保存的东西,会失去可读性。 许多调试器也不知道您指的是什么,因此调试更加困难。 它不会使程序运行得更快


考虑将语句中的代码与所引用对象的方法结合起来。

在工作中,我们给出了从现有Win 32代码库中删除with的要点,因为维护使用with的代码需要付出额外的努力。我在以前的一个作业中发现了几个bug,其中一个名为BusinessComponent的局部变量被隐藏在具有相同类型的已发布属性BusinessComponent的对象的With begin块中。编译器选择使用published属性,而打算使用局部变量的代码崩溃

我见过这样的代码

与a、b、c、d连用{除了它们是更长的名字,只是在这里缩短了) 开始 i:=xyz;
结束

试图找到xyz的来源是一件非常痛苦的事情。如果它是c,我会很快把它写成c

i:=c.xyz

您认为理解这一点非常简单,但对于一个在开始时使用with right的800行长的函数来说就不是了!

with不太可能使代码运行得更快,编译器更有可能将其编译为相同的可执行代码

人们不喜欢“with”的主要原因是它可能会混淆名称空间范围和优先级

有些情况下,这是一个真正的问题,有些情况下,这是一个非问题(非问题的情况将在问题中描述为“合理使用”)


由于可能的混淆,一些开发人员选择完全避免使用“with”,即使在没有这种混淆的情况下也是如此。这可能看起来很教条,但是可以说,随着代码的变化和增长,“with”的使用可能会保留,即使在代码被修改到一定程度后,也会使“with”的使用变得更加简单令人困惑,因此最好不要首先介绍它的用法。

我们最近在Delphi编码标准中禁止了它

利往往大于弊

也就是说,错误是因为它被误用而引入的。这并不能证明编写或执行代码所节省的时间是合理的

是的,使用with可以导致(稍微)更快的代码执行

在以下情况中,foo仅评估一次:

with foo do
begin
  bar := 1;
  bin := x;
  box := 'abc';
end
但是,这里对其进行了三次评估:

foo.bar := 1;
foo.bin := x;
foo.box := 'abc';
…跑得更快。。。 不一定-您的编译器/解释器通常比您更擅长优化代码


我想这会让我说“恶心!”因为它很懒——当我阅读代码(尤其是其他人的代码)时,我喜欢看到显式的代码。所以我甚至会在Java中编写“this.field”而不是“field”。

这主要是一个维护问题

从语言的角度来看,WITH的想法是合理的,并且认为WITH使代码在合理使用时变得更小、更清晰的观点是有一定道理的。然而,问题是,大多数商业代码在其生命周期中将由几个不同的人维护,当随着时间的推移,writed可以很容易地变异成笨拙的大型结构,其中WITH的范围不容易被维护人员解析。这自然会产生bug,并且很难找到bug

例如,假设我们有一个小函数foo,它包含三行或四行代码,这些代码被包装在一个WITH块中,那么确实没有问题
with x := ARect do
begin
  x.Left := 0;
  x.Rigth := 0;
  ...
end;
with Object1, Object2, Object3 do
begin
  //... Confusing statements here
end
procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32);
begin
  with ARect do FillRectS(Left, Top, Right, Bottom, Value);
end;
procedure TBitmap32.FillRectS(const ARect: TRect; Value: TColor32);
begin
  FillRectS(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, Value);
end;
with MyRect do
begin
  Left := 0;
  Right := 0;
end;
var aRect: ^TRect;

aRect := @MyRect;
aRect^.Left := 0;
aRect^.Right := 0;
for i := 0 to ObjList.Count-1 do
  for j := 0 to ObjList[i].NestedList.Count-1 do
  begin
    ObjList[i].NestedList[j].Member := 'Toto';
    ObjList[i].NestedList[j].Count := 10;
  end;
for i := 0 to ObjList.Count-1 do
  for j := 0 to ObjList[i].NestedList.Count-1 do
  with ObjList[i].NestedList[j] do
  begin
    Member := 'Toto';
    Count := 10;
  end;
for i := 0 to ObjList.Count-1 do
  with ObjList[i] do
  for j := 0 to NestedList.Count-1 do
  with NestedList[j] do
  begin
    Member := 'Toto';
    Count := 10;
  end;
for i := 0 to ObjList.Count-1 do
begin
  Obj := ObjList[i];
  for j := 0 to Obj.NestedList.Count-1 do
  begin
    Nested := Obj.NestedList[j];
    Nested.Member := 'Toto';
    Nested.Count := 10;
  end;
end;