有关使用嵌套“With”的任何资源/教程Delphi 中的语句?
我正在尝试正确处理 delphi 中的 with 语句。
总的来说,做简单的事情似乎相当简单,但我有兴趣找到一些关于使用嵌套 with 语句的好的代码示例和/或教程。 EG
with object1, object2, etc... do
begin
statements
end;
我不确定以这种方式使用 with 语句时的优先顺序。
任何建议表示赞赏。
I am trying to come to grips with using with statements in delphi properly.
Overall it seems fairly simple to do simple things with but I am interested in finding some good code examples and/or tutorials on using nested with statements. E.G.
with object1, object2, etc... do
begin
statements
end;
What I am unsure of is the order of precedence when using with statements in such a manner.
Any advice is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我能给你的最好建议是:
永远不要使用“with”。
如果你想使用“with”,就躺下来直到这种感觉过去。
如果您想使用嵌套,请用锤子敲打您的手,直到这种愿望消失为止。
“with”只是一个等待发生的错误。改变与它一起使用的类可以改变代码的含义。它会产生不精确的语义,这总是不好的。
节省击键次数从来都不是使用“with”的好理由。现在多敲几下键盘,以后就能省去很多麻烦。
应避免使用“与”。
The best advice I can give you is:
Do not use with ever.
If you feel like using 'with', go and lie down until the feeling passes.
If you feel like using a nested with, pound your hand with a hammer until the desire goes away.
'with' is just a bug waiting to happen. Altering classes used with it can alter the meaning of your code. It creates imprecise semantics, and that is always bad.
Saving keystrokes is never a good reason to use 'with'. A few more keystrokes now will save you a lot of pain later.
'With' should be shunned.
在线参考的摘录指出:
An excerpt from the online reference states:
既然已经给出了足够的意见,我将尝试完全回答您的问题,尽管这个先前的答案回答了语法部分你的问题已经很好了。它对文档的引用解释了优先级顺序,以及其他有趣的内容关于与的规则。将其视为必读。
正如您可能已经理解的,(未嵌套的)
with
的唯一问题是,您可以寻址的成员,而不是寻址特定的实例成员。 Self
(或来自一个嵌套级别的实例)具有相同的名称,显然您不打算这样做:运行,并惊讶于表单的标题已更改。当然,
TControl
声明了一个Caption
属性,但该属性是受保护的,因此此代码中的Caption
引用了表单的属性。但下一个示例也不能保证设置按钮的标题:...因为也许
Button1
被声明为某种异国情调的按钮类型,它有一个标题,但是属性名称可以是Title
、Beschriftung
或Legende
。这些都是简单的示例,很容易修复并且几乎不需要调试。但考虑内存中记录和对象的非可视成员:这些错误很难调试,因为:去哪里看?当然,如果运气好的话,
Self
没有这样的成员,以防编译器发出警告:...但不要指望只会出现编译器捕获的错误。
这类错误非常很容易犯。由我,由你,以及由任何其他(有经验的)开发人员。特别是当您处理或使用正在构建或正在重构的代码时。显然,使用嵌套的
with
时,这些错误带来的调试问题会呈指数级增长。现在,与我们这里的其他人不同,我经常使用
with
,但仅限于固定的库类型,这些类型的成员永远不会被重命名。例如:TRect、TPoint、TMessage、TGridRect、TControl、TCanvas 等...即几乎所有 RTL 记录类型以及一些 VCL 类,但几乎从未在我自己的库类型上。如果您确实想使用with
,我建议如下:安全示例:
棘手示例:
糟糕的例子:
编辑:
我已经成为 no-with-camp 的成员。
我上面的例子假设
with
仅在向上方向存在危险,例如将 Child.Caption 与 Self.Caption 混合在一起。但最近,当我将一些代码从D7移植到XE2时,我遇到了向下的麻烦。实际上,使用上面的“安全示例”,确实如此:意图将
Width
设为Self
的宽度,但由于 XE2 的TRect
也有一个Width
成员,我不得不将代码重写为:结论:确实没有安全使用
with
。Now that there are enough opinions given, I will try to fully answer your question, though this previous answer answers the syntax part of your question pretty well already. Its reference to the documentation explains the order of precedence, as well as other interesting rules about with. Consider it as a mandatory read.
As you may have understood already, the only problem with (an unnested)
with
is that instead of addressing a specific instance member, you could be addressing a member ofSelf
(or of an instance from one nested level up) with the same name, which you obviously did not intend to:Run, and be surprised the form's caption is changed. Sure,
TControl
declares aCaption
property, but that one is protected, thusCaption
in this code refers to that of the form. But also the next example does not guarantee setting the caption of the button:... because maybe
Button1
is declared as some exotic button type which has a caption, but the property name could beTitle
,Beschriftung
, orLegende
.These are simple examples which are easily fixed and almost need no debugging. But consider non-visual members of in-memory records and objects: those mistakes are very hard to debug, because: where to look? Sure, with a little luck,
Self
does not have such member, in case the compiler will warn:... but do not expect to only make errors which are caught by the compiler.
These kind of mistakes are made very easily. By me, by you, and by any other (experienced) developer. Especially when you work on or work with code which is under construction or is being refactored. And obviously, with nested
with
s, the debugging problems from these mistakes are piling up to exponential proportions.Now, unlike the rest of us here, I use
with
quite often, but only on fixed library types which' members are never to become renamed. E.g.:TRect, TPoint, TMessage, TGridRect, TControl, TCanvas,
etc... I.e. on almost all RTL record types as well as some VCL classes, but almost never on my own library types. If you really wánt to usewith
, I suggest the following:Safe example:
Tricky example:
Bad example:
Edit:
I have become a member of the no-with-camp.
My examples above assume danger with
with
only in upward direction, like mixing up Child.Caption with Self.Caption. But recently, when porting some code from D7 to XE2, I experienced trouble in downward direction. Actually, using the 'safe example' from above, sure enough:Intending
Width
to be that ofSelf
, but since XE2'sTRect
has also aWidth
member, I had to rewrite the code to:Conclusion: There really is no safe usuage of
with
.Delphi 的
with
是有问题的——它的“不精确的语义”确实会给你带来麻烦。嵌套
与
... 天啊... 一场灾难即将发生。从来不需要嵌套版本德尔福13年。我将在接下来的几年里避免这样做。
编辑:
在其他关于
with
的讨论中,一些人指出新的语法会很好。一个起点is Vb.Net
with
:我有点不喜欢(这是我的品味问题),但它比 Delphi 的好得多。我在这些讨论中看到的替代语法的建议是:
Delphi's
with
is problematic - it's "imprecise semantics" really can bite you on the rear.Nested
with
... OMG... Is a disaster waiting to happen. Never needed the nested version on13 years of Delphi. And I'll avoid for the next years.
EDIT:
In other discusions about
with
, some pointed that a new syntax would be nice. An starting pointis Vb.Net
with
:I dislike (a matter of taste mine) a little, but it's much better than Delphi's. An suggestion of alternative syntax which I saw on those discussions is:
我什至不想这么说,但弄清楚范围规则如何工作并不难。最后范围获胜。总是。
但人类有这个问题,在心理学上称为块理论。当你的脑海中出现七件需要记住的事情时,其中一件会掉下来,因为你的大脑大约有 6 个本地寄存器来保存事情。想象一下简单的标识符
Foo
出现在这里:上面是对于与 EXPRESSION1、EXPRESSION2 相同的所有意图,请开始...。
因此,让我们看看像范围这样的简单规则如何在一段时间后变得过于复杂而难以遵循。假设我们正在使用的某个 delphi 应用程序具有以下级别的作用域:
use
子句中每个单元的单元作用域。更新 David 向我指出,我应该提到,我们实际上有 5+x 个范围,而不是上面的 6 个“范围”,其中 x 是您的
使用的长度
条款。现在,问题不是WITH语句不清楚,而是当你有6层词法作用域时,人类很容易迷失方向,如上所述,并且要求你不仅要知道
的所有地方Foo
已定义,因为如果您认为最里面的 With 语句定义了名为Foo
的内容,那么您的代码中就会出现相当令人讨厌且难以发现的错误。因此,我们有像尼克这样非常聪明、非常有能力的人,他们会说“永远不要与”一起使用等非常明智的事情。我 99% 同意 Nick 的观点。我还认为你可以说敌人不存在,这是 Delphi 开发人员必须以“RAD 风格”迭代地不断开发他们的应用程序的趋势,直到它们变成怪物。一个使用 200 个其他单元的单元是一团糟,每个单元都使用 200 个其他单元,这甚至会比肆意滥用
WITH
语句给您带来更多的痛苦。WITH
并不是糟糕代码中的全部问题,它只是 Delphi 开发人员帽子中最常见的蜜蜂。也许它比过大的uses-clauses更受关注,但在我的整个职业生涯中,依赖地狱和巨大的uses-clauses使生活变得比WITH
多100倍。所以我认为WITH被认为是有害的
做得太过了,而其他应该更多考虑的事情却没有被考虑。使用 with 的一个合理替代方案是使用单字母变量名(我知道,继续并不同意),并避免所有范围歧义:
很多人会说,这比这个更好:
现在我被 < 咬住了code>WITH 太多次,提倡不受限制地使用。但我也认为有时它实际上比执行局部变量更好。它不需要您声明局部变量或确定表达式的类型。如果delphi有
类型推断
(C++中的auto
关键字),那么我想说,我们可以轻松地完全不用WITH
,但是因为它是的,这是一种避免静态创建对实现类型的依赖的方法,并且除了创建可读子范围的能力之外,它有时会使代码更易于阅读,有时会使代码变得更糟,尤其是当存在超过一级WITH
语句。然而,对此事的看法各不相同,并且像其他编程主题一样,往往会变成自行车棚的讨论,或更糟糕的是,变成一场圣战。
我建议的规则:
避免
WITH
,除非它使你的代码更好。大多数您认为需要 with 的地方,实际上并不需要,而是使用局部变量。始终避免多级
WITH
语句。I hate to even say this, but it's not exactly hard to figure out how scope rules work. Last scope in wins. Always.
But human beings have this problem, which in psychology is called Chunk Theory. When you are presented with seven things to keep track of in your mind, one falls out, because your brain has about 6 local registers to keep things in. Imagine the simple identifier
Foo
appears here:The above is for all intents identical to
with EXPRESSION1, EXPRESSION2 do begin...
.So let's see how simple rules like scope get too complicated to follow after a while. Let's imagine that we have the following levels of scope in some delphi application we're working in:
use
clauses.Update David has pointed out to me that I should mention that instead of 6 "scopes" above, we really have 5+x scopes, where x is the length of both your
uses
clauses.Now, the problem isn't the WITH statement being unclear, it's that human beings can easily get lost when you have 6 layers of lexical scoping going on, as above, and requires you not only to be aware of all places where
Foo
is defined, because if you thought that the innermost With statement has something namedFoo
defined, and it doesn't you get a rather nasty and hard to find bug in your code. And so, we have very smart, very capable people like Nick, saying very sensible things like "never use with". And I agree about 99% with Nick.I also think that you could say that the enemy is not with, it's the tendency Delphi developers have to just keep growing their applications iteratively in a "RAD style" until they have become monstrosities. A unit which uses 200 other units is a mess, each of which uses 200 other units, is going to cause you more grief even than rampant abuse of
WITH
statements.WITH
is not the entire problem in bad code, it's just the most common bee in a Delphi developer's bonnet. Maybe it gets more attention than over-large uses-clauses, but over my entire career, dependency-hell and enormous-uses-clauses have done 100 times more to make life hard, thanWITH
. So I think thatWITH considered harmful
is over-done, and other things which ought to be considered more, are under considered.A reasonable alternative to using with, is to use a single letter variable name (I know, go ahead and disagree), and avoid all scope ambiguity:
That is better, many would say, than this:
Now I've been bitten by
WITH
too many times to advocate its unrestricted use. But I also think there are times when it's actually better than doing the local variable stuff. It doesn't require that you declare a local variable, or determine the type of the expression. If delphi hadtype inference
(theauto
keyword in C++), then I would say, we could easily do withoutWITH
completely, but as it is, it is kind of a way to avoid statically creating a dependency on implementation types, and along with the ability to create readable sub-scopes, it can sometimes make your code easier to read, and sometimes make it worse, especially when there is more than one level ofWITH
statements.However, opinions on that matter vary, and like other programming topics, tends to turn into a bike-shed discussion, or worse yet, a holy war.
My suggested rules:
Avoid
WITH
unless it makes your code better. Most places that you think you need a with, you don't, use a local variable instead.Always avoid multi-level
WITH
statements.