Delphi 为什么我不应该使用;加上;在德尔菲?
我听过很多程序员,特别是Delphi程序员对“with”的使用不屑一顾 我认为它使程序运行得更快(只对父对象进行了一次引用),而且如果使用得当(不到十几行代码且没有嵌套),读取代码也更容易 下面是一个例子: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; 我喜欢将与一
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;