德尔福是“与”吗? 关键字是不好的做法吗?

发布于 2024-07-13 17:14:01 字数 1457 浏览 14 评论 0原文

我一直在读有关 delphi 中 with 关键字的坏话,但在我看来,如果你不过度使用它。 它可以让你的代码看起来很简单。

我经常将所有 TClientDataSet 和 TField 放在 TDataModule 中。 因此,在我的表单中,我有这样的代码

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule do
  begin
     LongNameTable1.Insert;
     LongNameTable1_Field1.Value := "some value";
     LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
     LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
     LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
     LongNameTable1.Post;
  end
end;

,没有 with 关键字,我必须编写这样的代码,

    procedure TMyForm.AddButtonClick(Sender: TObject);
    begin            
      LongNameDataModule.LongNameTable1.Insert;
      LongNameDataModule.LongNameTable1_LongNameField1.Value := "some value";

      LongNameDataModule.LongNameTable1_LongNameField2.Value :=
               LongNameDataModule.LongNameTable2_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField3.Value :=
               LongNameDataModule.LongNameTable3_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField4.Value :=
               LongNameDataModule.LongNameTable4_LongNameField1.Value;

      LongNameDataModule.LongNameTable1.Post;
    end;

我认为使用 with 关键字更容易阅读。

我应该避免使用 with 关键字吗?

I been reading bad things about the with keyword in delphi but, in my opinion, if you don't over use it. It can make your code look simple.

I often put all my TClientDataSets and TFields in TDataModules. So in my forms I had code like this

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule do
  begin
     LongNameTable1.Insert;
     LongNameTable1_Field1.Value := "some value";
     LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
     LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
     LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
     LongNameTable1.Post;
  end
end;

without the with keyword I have to write the code like this

    procedure TMyForm.AddButtonClick(Sender: TObject);
    begin            
      LongNameDataModule.LongNameTable1.Insert;
      LongNameDataModule.LongNameTable1_LongNameField1.Value := "some value";

      LongNameDataModule.LongNameTable1_LongNameField2.Value :=
               LongNameDataModule.LongNameTable2_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField3.Value :=
               LongNameDataModule.LongNameTable3_LongNameField1.Value;

      LongNameDataModule.LongNameTable1_LongNameField4.Value :=
               LongNameDataModule.LongNameTable4_LongNameField1.Value;

      LongNameDataModule.LongNameTable1.Post;
    end;

I think is easier to read using the with keyword.

Should I avoid using the with keyword?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

杀お生予夺 2024-07-20 17:14:01

除了像“with A、B、C、D”这样的病态条件之外,with 的最大危险是你的代码可以在不通知你的情况下悄悄改变含义。 考虑这个例子:

with TFoo.Create
try
  Bar := Baz;
  DoSomething();
finally
  Free;
end;

您编写此代码时知道 Bar 是 TFoo 的属性,而 Baz 是包含具有此代码的方法的类型的属性。

现在,两年后,一些善意的开发人员加入,为 TFoo 添加了 Baz 属性。 你的代码已经悄然改变了意义。 编译器不会抱怨,但代码现在已损坏。

The biggest danger of with, outside of pathological conditions like "with A, B, C, D" is that your code can silently change meaning with no notice to you. Consider this example:

with TFoo.Create
try
  Bar := Baz;
  DoSomething();
finally
  Free;
end;

You write this code knowing that Bar is a property of TFoo, and Baz is a property of the type containing the method which has this code.

Now, two years later, some well-meaning developer comes in adds a Baz property to TFoo. Your code has silently changed meaning. The compiler won't complain, but the code is now broken.

鲜血染红嫁衣 2024-07-20 17:14:01

with 关键字是一个很好的功能,可以使代码更具可读性,但也存在一些缺陷。

调试:

当使用这样的代码时:

with TMyClass.Create do
try
  Add('foo');
finally
  Free;
end;

无法检查此类的属性,因此始终声明一个变量并使用with关键词。

接口:

with子句中创建接口时,它会一直存在到方法的末尾:

procedure MemoryHog;
begin
  with GetInterfaceThatTakes50MBOfMemory do
    Whatever;
  ShowMessage('I''m still using 50MB of memory!');
end;

清晰度

当在 with 子句中使用具有范围内已存在的属性或方法名称的类时,它很容易欺骗您。

with TMyForm.Create do
  Width := Width + 2; //which width in this with is width?

当然,当名称重复时,您将使用 with 语句 (TMyForm) 中声明的类的属性和方法。

The with keyword is a nice feature for making your code more readable but there are some pitfalls.

Debugging:

When using code like this:

with TMyClass.Create do
try
  Add('foo');
finally
  Free;
end;

There is no way to inspect the properties of this class, so always declare a variable and use the with keyword on that.

Interfaces:

When creating an interface in the with clause it lives till the end of your method:

procedure MemoryHog;
begin
  with GetInterfaceThatTakes50MBOfMemory do
    Whatever;
  ShowMessage('I''m still using 50MB of memory!');
end;

Clarity

When using a class in a with clause that has properties or method names that already exists within the scope, it can fool you easily.

with TMyForm.Create do
  Width := Width + 2; //which width in this with is width?

Of course when having duplicate names, you're using the properties and methods of the class declared in your with statement (TMyForm).

离不开的别离 2024-07-20 17:14:01

with 语句有其用武之地,但我必须承认过度使用会导致代码不明确。 一个好的经验法则是确保添加 with 语句后代码“更”可读和可维护。 如果您觉得在添加语句后需要添加注释来解释代码,那么这可能是一个坏主意。 如果代码像您的示例中那样更具可读性,则使用它。

顺便说一句:这一直是我在 Delphi 中最喜欢的显示模式窗口的模式之一

with TForm.Create(nil) do
try
  ShowModal;
finally
  Free;
end

The with statement has its place but I have to agree that overuse can lead to ambiguous code. A good rule of thumb is to make sure the code is "more" readable and maintainable after adding the with statement. If you feel you need to add comments to explain the code after adding the statement then it is probably a bad idea. If the code is more readable as in your example then use it.

btw: this was always one of my favorite patterns in Delphi for showing a modal window

with TForm.Create(nil) do
try
  ShowModal;
finally
  Free;
end
回忆躺在深渊里 2024-07-20 17:14:01

我倾向于完全禁止 with 语句。 如前所述,它会使事情变得复杂,我的经验是它会的。 很多时候,调试器因为 withs 而需要计算值,而且我经常发现嵌套的 withs 会导致代码难以阅读。

Brian 的代码看起来可读且不错,但是如果您直接对发送者进行类型转换,则代码会更短,并且消除了对启用的该组件的所有疑问:

TAction(Sender).Enabled := Something;

如果您担心输入太多,我会暂时参考长命名对象:

var
  t: TTable;
begin
  t := theLongNamedDataModule.WithItsLongNamedTable;
  t.FieldByName(' ');
end;

不过,我不明白为什么打字会打扰你。 我们首先是打字员,其次是程序员,以及代码完成、复制粘贴和按键记录可以帮助您成为一名更高效的打字员。

更新:
刚刚偶然发现了一篇长文章,其中有一小部分是关于 with 语句的: 他用关键字。 该语言中最丑陋、最危险、最令人震惊的功能。 :-)

I tend towards baning the with-statement altogether. As previously stated, it can make things complicated, and my experience is that it will. Many times the debugger want evaluate values because of withs, and all to often I find nested withs that lead to code that hard to read.

Brian's code seems readable and nice, but the code would be shorter if you just typecast the sender directly, and you remove all doubt about that component you enable:

TAction(Sender).Enabled := Something;

If you are concerned about typing to much, I prefare to make a temporary referance to the long-named object:

var
  t: TTable;
begin
  t := theLongNamedDataModule.WithItsLongNamedTable;
  t.FieldByName(' ');
end;

I can't se why typing should bother you, though. We Are Typists First, Programmers Second, and code-completion, copy-paste and key-recording can help you be a more effective typist.

update:
Just stumbled over an long article with a little section on with-statements: he with keyword. The most hideous, dangerous, blow-your-own-feet-off feature in the language. :-)

街道布景 2024-07-20 17:14:01

当我第一次开始 Pascal 编程(使用 TurboPascal!)并边学边学时,WITH 看起来很棒。 正如你所说,这是繁琐打字的答案,也是那些长记录的理想选择。 自从 Delphi 出现以来,我一直在删除它并鼓励其他人放弃它 - Verity 在 注册
除了可读性降低之外,我避免使用它还有两个主要原因:

  1. 如果您使用类,那么您无论如何都不需要它 - 只有记录“似乎”可以从中受益。
  2. 使用调试器通过 Ctrl-Enter 跟踪代码到声明是行不通的。

也就是说,为了可读性,我仍然使用语法:

procedure ActionOnUpdate( Sender : TObject )
begin
  With Sender as TAction do
    Enabled := Something
end;

我还没有看到更好的构造。

When I first began pascal programming (with TurboPascal!) and learnt as I went, WITH seemed wonderful. As you say, the answer to tedious typing and ideal for those long records. Since Delphi arrived, I've been removing it and encouraging other to drop it - neatly summed-up by Verity at the register
Apart from a reduction in readability there are two main reasons why I'd avoid it:

  1. If you use a class then you dont need it anyway - only records 'seem' to benefit from it.
  2. Using the debugger to follow the code to the declaration with Ctrl-Enter doesnt work.

That said, for readability I still use the syntax:

procedure ActionOnUpdate( Sender : TObject )
begin
  With Sender as TAction do
    Enabled := Something
end;

I've not seen a better construct.

小鸟爱天空丶 2024-07-20 17:14:01

在我看来,您的示例(通过单击按钮访问数据模块)是一个设计不当的示例。 如果您将此代码移至数据模块应有的位置,则对WITH 的全部需求就消失了。 OnClick 然后只调用 LongNameDataModule.InsertStuff 并且不需要。

With 是一个很差的设备,您应该查看代码以了解为什么需要它。 您可能做错了什么,或者可以采取更好的方法。

Your example, of a datamodule access within a button click, is a poorly contrived example in my opinion. The whole need for WITH goes away if you move this code into the data module where it should be. The OnClick then just calls LongNameDataModule.InsertStuff and there is no with needed.

With is a poor device, and you should look at your code to see why you are needing it. You probably did something wrong, or could do it a better way.

忘东忘西忘不掉你 2024-07-20 17:14:01

正如 Vegar 提到的,使用临时引用同样简洁、更具可读性、更容易调试,并且不太容易出现隐秘问题。

到目前为止,我从未发现需要使用with。 我曾经对此很矛盾,直到我接手了一个经常使用思维扭曲双重的项目。 质疑原始开发人员是否打算引用第一个 with 或第二个中的项目,如果该模糊引用是 with-slip 或笨拙的代码,则尝试调试它是一种痛苦,并且扩展或修改使用这些令人厌恶的类的连锁反应是不值得任何人花时间的。

显式代码简单更具可读性。 这样你就可以吃到蛋糕并享受吃的乐趣了。

procedure TMyForm.AddButtonClick(Sender: TObject);
var
  dm: TLongNameDataModuleType
begin  
  dm:=LongNameDataModule;

  dm.LongNameTable1.Insert;
  dm.LongNameTable1_Field1.Value := "some value";
  dm.LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  dm.LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  dm.LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  dm.LongNameTable1.Post;
end;

As Vegar mentioned, it's just as neat and much more readable, easier to debug, and less prone to stealth issues to use a temporary reference.

So far, I have never found a need to use with. I used to be ambivalent over it, until I took over a project that used the mind bending double with frequently. Questioning whether the original developer intended to reference items in the first with or second, if that ambiguous reference was a with-slip or clumsy code, the torment of trying to debug it, and the knock on effects of extending or modifying classes that use these abominations is just not worth anyone's time.

Explicit code is simply more readable. This way you can have your cake and enjoy eating it.

procedure TMyForm.AddButtonClick(Sender: TObject);
var
  dm: TLongNameDataModuleType
begin  
  dm:=LongNameDataModule;

  dm.LongNameTable1.Insert;
  dm.LongNameTable1_Field1.Value := "some value";
  dm.LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  dm.LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  dm.LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  dm.LongNameTable1.Post;
end;
维持三分热 2024-07-20 17:14:01

我坚信在 Delphi 中删除WITH 支持。 您使用带有命名字段的数据模块的示例用法大约是我能看到它工作的唯一实例。 除此之外,反对它的最佳论据是克雷格·斯图茨(Craig Stuntz)提出的——我投了赞成票。

我只是想指出,随着时间的推移,您可能最终(应该)删除 OnClick 事件中的所有编码,并且您的代码最终也将从数据模块上的命名字段迁移到使用包装此数据的类,并且使用 WITH 的原因将消失。

I'm a firm believer of removing WITH support in Delphi. Your example usage of using a datamodule with named fields is about the only instance I could see it working out. Otherwise the best argument against it was given by Craig Stuntz - which I voted up.

I just like to point out that over time you may eventually (should) rmeove all coding in OnClick events and your code will also eventually migrate away from named fields on datamodules into using classes that wrap this data and the reason to use WITH will go away.

丢了幸福的猪 2024-07-20 17:14:01

你的问题是“锤子并不总是解决方案”的一个很好的例子。

在这种情况下,“with”不是您的解决方案:您应该将此业务逻辑从表单移至数据模块中。
不这样做违反了德米特法则,就像mghie(Michael Hieke)已发表评论。

也许您的示例只是说明性的,但如果您实际上在项目中使用类似的代码,那么您应该这样做:

procedure TLongNameDataModule.AddToLongNameTable1(const NewField1Value: string);
begin  
  LongNameTable1.Insert;
  LongNameTable1_Field1.Value := NewField1Value;
  LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  LongNameTable1.Post;
end;

然后从您的表单中调用它,如下所示:

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  LongNameDataModule.AddToLongNameTable1('some value');
end;

这有效地摆脱了您的 with 语句,并使同时你的代码更易于维护。

当然,用单引号包围 Delphi 字符串也将有助于编译;-)

Your question is an excellent example of 'a hammer is not always the solution'.

In this case, 'with' is not your solution: You should move this business logic out of your form into your datamodule.
Not doing so violates Law of Demeter like mghie (Michael Hieke) already commented.

Maybe your example was just illustrative, but if you are actually using code like that in your projects, this is what you should do in stead:

procedure TLongNameDataModule.AddToLongNameTable1(const NewField1Value: string);
begin  
  LongNameTable1.Insert;
  LongNameTable1_Field1.Value := NewField1Value;
  LongNameTable1_Field2.Value := LongNameTable2_LongNameField1.Value;
  LongNameTable1_Field3.Value := LongNameTable3_LongNameField1.Value;
  LongNameTable1_Field4.Value := LongNameTable4_LongNameField1.Value;
  LongNameTable1.Post;
end;

And then call it from your form like this:

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  LongNameDataModule.AddToLongNameTable1('some value');
end;

This effectively gets rid of your with statement, and makes your code more maintainable at the same time.

Of course surrounding Delphi strings with single quotes will help making it compile as well ;-)

丑丑阿 2024-07-20 17:14:01

“with”的主要问题是您不知道它的范围在哪里结束,并且您可能有多个重叠的 with 语句。

我认为只要您的代码可读,您就不应该避免使用它。

使其更具可读性(并且在较长的代码中减少混乱)的建议之一是,如果 codegear 添加 选项 以允许在 with 中使用别名,并且可能允许在一个中使用多个 with:

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule as dm, dm.LongNameTable1 as t1, dm.LongNameTable2 as t2 do
  begin
    t1.Insert;
    t1.FieldByName('Field1').AsString := 'some value';
    t1.FieldByName('Field2').AsString := t2.FieldByName('Field2').AsString;
    t1.Post;
    dm.Connection.Commit;
  end
end;

The main problem with "with" is that you don't know where its scope ends, and you could have multiple overlapping with statements.

I don't think you should avoid using it, as long as your code is readable.

One of the proposals to make it more readable (and less confusing in longer code) was if codegear added the option to allow for aliases in with, and probably allowing multiple withs in one:

procedure TMyForm.AddButtonClick(Sender: TObject);
begin  
  with LongNameDataModule as dm, dm.LongNameTable1 as t1, dm.LongNameTable2 as t2 do
  begin
    t1.Insert;
    t1.FieldByName('Field1').AsString := 'some value';
    t1.FieldByName('Field2').AsString := t2.FieldByName('Field2').AsString;
    t1.Post;
    dm.Connection.Commit;
  end
end;
牛↙奶布丁 2024-07-20 17:14:01

就我而言,在你给出的情况下,With 是完全可以接受的。 它确实提高了代码的清晰度。

真正的邪恶是当你同时打开多个 with 时。

另外,我的观点是,您使用的 with on 会产生很大的差异。 如果它是一个真正不同的对象,那么 with 可能是一个坏主意。 然而,我不喜欢在一个级别上有很多变量,即使这是有意义的——通常是保存整个非常复杂的数据项的数据对象——通常是程序设计用来处理的整个工作。 (我认为这种情况不会发生在没有此类项目的应用程序中。)为了让世界更清晰,我经常使用记录对相关项目进行分组。 我发现我使用的几乎所有 with 都是为了访问此类子组。

As far as I'm concerned, With is quite acceptable in the case you give. It certainly improves the code clarity.

The real evil is when you have multiple with's open at once.

Also, my opinion is that what you are using the with on makes a big difference. If it's a truly different object then the with is probably a bad idea. However, I dislike having a lot of variables at one level even when this makes sense--generally data objects that hold an entire very complex data item--generally the entire piece of work the program is designed to work with. (I do not think this case would occur in an app that didn't have such an item.) To make the world clearer I often use records to group related items. I find that almost all withs I use are for accessing such subgroups.

妄断弥空 2024-07-20 17:14:01

关于为什么 with 语句不好,这里有很多很好的答案,所以我尽量不重复它们。 我多年来一直使用 with 语句,但现在我开始回避它。 部分原因是确定范围可能很困难,但我最近开始进行重构,并且没有一个自动重构可以与 with 语句一起使用 - 而且自动重构非常棒。

另外,前段时间我制作了一个视频,解释为什么 with 语句不好,它不是我最好的作品之一,但 这里

There are many excelent answers here as to why the with statement is bad, so I'll try not to repeat them. I've been using the with statement for years and I'm very much starting to shy away from it. This is partially beause it can be difficult to work out scope, but I've been starting to get into refactoring lately, and none of the automated refactorings work withing a with statement - and automated refactoring is awesome.

Also some time ago I made a video on why the with statement is bad, it's not one of my best works but Here it is

南笙 2024-07-20 17:14:01

仅临时使用 with (就像您临时注释掉一样)。

它可以帮助您编写代码草图以快速编译和运行某些内容。 如果合并解决方案,请将其清理干净! 当您将代码移动到正确的位置时,删除 with

Use with only temporarily (just as you comment-out temporarily).

It helps you write code sketches to get something compiled and running fast. If you consolidate the solution, clean it up! Remove with as you move code to the right place.

断舍离 2024-07-20 17:14:01

当前的 With 语句是“危险的”,但它可以得到实质性改进:

  With TForm1.Create (Nil) Do  // New TForm1 instance
    Try
      LogForm (");  // That same instance as parameter to an outer method
      "ShowModal;  // Instance.ShowModal
    Finally
      "Free;  // Instance.Free
    End;

我的建议是:

  1. 每个 With 标头不超过一个对象/记录。
  2. 不允许嵌套。
  3. 使用 " 来指示对象/记录(双引号类似
    到同上标记:http://en.wikipedia.org/wiki/Ditto_mark)。

The current With statement is "dangerous", but it can be substantially improved:

  With TForm1.Create (Nil) Do  // New TForm1 instance
    Try
      LogForm (");  // That same instance as parameter to an outer method
      "ShowModal;  // Instance.ShowModal
    Finally
      "Free;  // Instance.Free
    End;

My proposal is:

  1. No more than one object/record per With header.
  2. Nested Withs not allowed.
  3. Usage of " to indicate the object/record (double quotes are similar
    to the ditto mark: http://en.wikipedia.org/wiki/Ditto_mark).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文