为什么省略大括号被认为是不好的做法?

为什么每个人都告诉我写这样的代码是不好的做法?

if (foo) Bar(); //or for(int i = 0 i < count; i++) Bar(i); 

我忽略大括号的最大理由是它有时可能是它们的两倍。 例如,下面是一些在C#中为标签绘制发光效果的代码。

 using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor))) { for (int x = 0; x <= GlowAmount; x++) { for (int y = 0; y <= GlowAmount; y++) { g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y)); } } } //versus using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor))) for (int x = 0; x <= GlowAmount; x++) for (int y = 0; y <= GlowAmount; y++) g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y)); 

您还可以获得链接使用的额外好处,而不必缩进一百万次。

 using (Graphics g = Graphics.FromImage(bmp)) { using (Brush brush = new SolidBrush(backgroundColor)) { using (Pen pen = new Pen(Color.FromArgb(penColor))) { //do lots of work } } } //versus using (Graphics g = Graphics.FromImage(bmp)) using (Brush brush = new SolidBrush(backgroundColor)) using (Pen pen = new Pen(Color.FromArgb(penColor))) { //do lots of work } 

花括号最常见的参数是围绕着维护编程,以及在原始if语句和预期结果之间插入代码所带来的问题:

 if (foo) Bar(); Biz(); 

问题:

  1. 想要使用语言提供的更紧凑的语法是错误的吗? devise这些语言的人是聪明的,我无法想象他们会把一个总是不好用的function。
  2. 我们是否应该或不应该编写代码,以使最低公分母能够理解并且没有问题?
  3. 还有另外一个我失踪的说法吗?

实际上,唯一真正有点时间的是当我debugging时,注释掉bar():

 if(foo) // bar(); doSomethingElse(); 

除此之外,我倾向于使用:

 if(foo) bar(); 

哪个照顾上述情况。

编辑感谢澄清的问题,我同意,我们不应该写代码到最低的共同点。

阅读速度…

除了已经提到的。 在这一点上,我已经习惯于parsing带有大括号和空格的陈述。 所以我读到:

 if (condition) { DoSomething(); } DoSomethingElse(); 

稍微比我读的更快:

 if (condition) DoSomething(); DoSomethingElse(); 

如果看起来像这样,我读得慢一点:

 if (condition) DoSomething(); DoSomethingElse(); 

我读到这比之前显着慢:

 if (condition) DoSomething(); DoSomethingElse(); 

因为我忍不住再读一遍,只是想知道作者是否打算:

 if (condition) { DoSomething(); DoSomethingElse(); } 

已经涵盖了一般情况,但是在阅读下面的内容时,我会仔细研究这一点,以确定作者的意图。 我甚至可以追捕原作者确认。

 if (condition) DoSomething(); DoSomethingElse(); 

如果它是小的话,就像这样写:

 if(foo()) bar(); 

如果它足够长,可以分成两行,使用大括号。

我也曾经认为只有在需要时才使用大括号。 但现在不是了,主要的原因是,当你有很多代码时,它确实使它更具可读性,当你有一致的支撑风格时,你可以更快地parsing代码。

总是使用大括号的另一个很好的理由,除了有人添加第二个陈述,是这样的事情可能会发生:

 if(a) if(b) c(); else d(); 

你有没有注意到else语句其实就是“if(b)”的那个? 你可能做到了,但是你会相信任何人熟悉这个问题吗?

所以,如果仅仅为了一致性,并且因为你永远不知道别人 (总是其他人是愚蠢的)会发生什么样的意想不到的事情,所以我改变了代码,因为它使得源代码更具可读性,更快地parsing你的脑。 只有最简单的if语句,比如一个委托是做什么的,或者是一个切换式的,如果你知道这个从句是永远不会被扩展的,那么我会省去大括号。

我更喜欢大括号提供的清晰度。 你确切地知道是什么意思,不必猜测某人是否被愚蠢地抛弃了(并引入了一个bug)。 当我把if和action放在同一行时,我只会忽略它们。 我也不经常这样做。 实际上,我更喜欢将大括号引入到自己的行中,尽pipe从多年来的K&R C类编程中,用括号结束行是一个练习,我必须努力克服,如果IDE不强制执行它我。

 if (condition) action(); // ok by me if (condition) // normal/standard for me { action(); } 

这并不总是被认为是不好的做法。 如果没有必要, Mono项目编码指南build议不要使用花括号。 GNU编码标准也一样 。 我认为这一直是编码标准的一个个人品味问题。

线路便宜。 处理器的功耗很便宜。 开发人员的时间非常昂贵。

作为一般规则,除非我正在开发一些绝对的资源/速度关键应用程序,否则我总是会犯错

(a)任何其他开发者都可以轻松地遵循我正在做的事情

(b)评论可能需要的代码的特定部分

(c)如果出现问题,便于debugging

(d)如果将来需要修改,则易于修改(即添加/删除代码)

从商业angular度来看,代码的速度或学术优雅次于这些因素。 这并不是说我开始写出笨重或难看的代码,但这是我的优先顺序。

在大多数情况下省略大括号,这使我(b),(c)和(d)更加困难(注意不是不可能)。 我会说使用大括号或不使用(a)。

我认为这是你正在从事的项目和个人品味的准则。

我通常在不需要的时候忽略它们,除了以下情况:

 if (something) just one statement; // i find this ugly else { // many // lines // of code } 

我更喜欢

 if (something) { just one statement; // looks better:) } else { // many // lines // of code } 

其中一个可以咬你的例子是在C / C ++macros的旧时代。 我知道这是一个C#的问题,但是编码标准往往没有标准创build的原因。

如果您在创buildmacros时不太在意,则最终可能会导致if语句不使用{}。

 #define BADLY_MADE_MACRO(x) function1(x); function2(x); if (myCondition) BADLY_MADE_MACRO(myValue) 

现在,不要误解我的意思,我不是说你总是应该避免在C / C ++中出现这个问题,但是我必须处理一些非常奇怪的错误。

我用同样的方式思考。

直到有一天(为什么总有那么一天会改变你的生活呢?)我们从24小时到36小时不花时间debugging生产代码,只发现有人没有把大括号与search/replace改变结合起来。

这是这样的。

  if( debugEnabled ) println( "About to save 1 day of work to some very important place."); saveDayData(); 

之后是什么

  if( debugEnabled ) // println( "About to save 1 day of work to some very important place."); saveDayData(); 

事实certificate,该系统每天产生500MB的日志,我们被要求停止。 debugging标志是不够的,所以search和replaceprintln是为了。

仍然当应用程序进入生产debugging标志closures,重要的“saveDayData”从来没有被调用。

编辑

现在唯一不使用大括号的地方是if / try构造。

 if( object != null ) try { object.close(); } catch( ..... 

看了一个超级明星开发者这样做。

我很高兴:

 foreach (Foo f in foos) foreach (Bar b in bars) if (f.Equals(b)) return true; return false; 

就我个人而言,我不明白为什么

 foreach (Foo f in foos) { foreach (Bar b in bars) { if (f.Equals(b)) { return true; } } } return false; 

更可读。

是的,行是免费的,但为什么我应该滚动页面和代码页时,它可能是一半的大小?

如果在可读性或可维护性方面存在差异,那么当然,把括号放进…但是在这种情况下,我没有看到任何理由。

另外,我会一直戴嵌套如果是括号嵌套其他的

 if (condition1) if (condition2) doSomething(); else (condition2) doSomethingElse(); 

VS

 if (condition1) if (condition2) doSomething(); else (condition2) doSomethingElse(); 

是非常混乱,所以我总是写作:

 if (condition1) { if (condition2) doSomething(); else (condition2) doSomethingElse(); } 

只要有可能,我使用三元操作符,但是我绝不会 嵌套它们 。

直言,我把它看成是:

好的程序员防守程序,坏的程序员不会。

既然上面有几个例子,而且我自己也有类似的经验,那就是与忘记大括号有关的错误,于是我学会了总是放弃支撑的难题。

还有就是select个人风格而不是安全,这显然是不好的编程。

Joel甚至在错误代码错误中提到这一点

一旦你因为缺less大括号而被一个错误所困扰,你会发现错误的大括号看起来是错误的,因为你知道这是另一个错误发生的潜在的地方。

我同意“如果你足够聪明,可以让某人付钱给你编写代码,那么你应该足够聪明,不要只依靠缩进来看代码的stream向。”

然而…错误是可以做出来的,而且这是一个很难debugging的问题,特别是如果你正在看别人的代码。

我的哲学是如果它使代码更可读,为什么不做呢?

很明显,你必须在某个地方画线,就像在简明的和过度描述的variables名称之间find一个快乐的媒介一样。 但括号确实可以避免错误并提高代码的可读性。

你可以争辩说,足够聪明的人作为编码人员将足够聪明,以避免出现无支架语句的错误。 但是,你能诚实地说,你从来没有被拼写错误那么简单的事情绊倒吗? 当看大型项目时,这样的细节可能会变得非常困难。

总是有例外,但是我会反对只有在以下forms之一时才会省略大括号:

 if(x == y) for(/* loop */) { //200 lines } //rampion's example: for(/* loop */) { for(/* loop */) for(/* loop */) { //several lines } } 

否则,我没有问题。

我偶尔使用最底层的代码(使用多个语句),但除此之外,我总是使用大括号。我只是发现它使代码更清晰。 从声明中可以明显看出,声明是块的一部分(因此可能是if等的一部分)。

我已经看到了

 if (...) foo(); bar(); 

臭虫咬我(或者说“我和同事” – 我实际上没有引入这个bug) 一次 。 尽pipe我们的编码标准在当时推荐使用大括号。 我花了很长时间才发现 – 因为你看到了你想看的东西。 (这是大约十年前的事,现在也许我会更快地find它)

当然,如果你使用“在线末端”,减less了额外的线,但我个人不喜欢这种风格。 (我在工作中使用它,发现它比我想象的更不愉快,但它仍然有点不愉快。)

在三个公约中:

 if(addCurleyBraces()) bugFreeSofware.hooray(); 

和:

 if(addCurleyBraces()) bugFreeSofware.hooray(); 

和(它表示使用开始和结束大括号的任何缩进样式):

 if(addCurleyBraces()) { bugFreeSofware.hooray(); } 

我更喜欢最后一个:

  • 如果所有的if语句都是以统一的方式写的,我发现读起来更容易。
  • 它可能使软件更健壮一点,并且没有bug。 然而,所有现代的IDE和高级文本编辑器都具有很好的自动缩进function,我认为每个人都应该使用,只要它不会混乱注释格式或违反团队标准(在很多情况下,可以创build自定义格式化scheme并与团队分享)。 我的意思是,如果缩进是正确完成的,那么bug引入的风险会降低一点。
  • 我更喜欢布尔expression式和语句执行在不同的行上。 我喜欢为了debugging目的而标记一行。 即使我正在使用一个IDE来标记一个语句并进行一步操作,这是一个交互操作,我可能会忘记从哪里开始进行debugging,或者至less需要多一点时间才能遍历代码次(因为我必须在debugging过程中每次手动标记位置)。

我对这个计算机编程领域的同行(你很多)不会因为潜在的错误而望而却步。

我想这意味着我不聪明。 我多次犯了这个错误。 我已经debugging过其他人的错误。 我曾经看过软件,因为这个错误(RDP到一台运行VS2002的机器,你的观察窗口的字体会变得不可思议)。

如果我看到我所做的所有错误都可以通过改变编码风格来避免,那么这个列表很长。 如果在这些情况下我没有改变我的方法,我可能永远不会成为程序员。 再次,我想我不聪明。 为了弥补,我长期以来一直是单线路障碍的坚定使用者。

也就是说,世界上有些事情已经改变了,使得“在单行方块上使用括号”的规则今天比摩西把它带给我们的规则更不重要:

  • 一些stream行的语言通过使计算机读取缩进来解决问题,就像程序员所做的那样(例如Python)。

  • 我的编辑器会自动为我设置格式 ,所以我缩进的机会大大减less了。

  • TDD意味着如果我因为单行块而感到困惑而引入了一个bug,我很可能会很快发现这个bug。

  • 重构和语言performance力意味着我的块要短得多,单行块比以前要多得多。 假设,通过ExtractMethod的无情应用,我可能在整个程序中只有单行块。 (我不知道会是什么样子?)

实际上,在单行块上重构和省略花括号可以带来明显的好处:当你看到花括号的时候,你的头上可能会出现一个小小的警告,指出“这里的复杂性!小心!”。 想象一下,如果这是常态:

 if (condition) Foo(); // normal, everyday code if (condition) { // something non-trivial hapening; pay attention! Foo(); Bar(); } 

我打开自己的想法,改变我的编码约定,像“单行块可能永远不会有大括号”或“如果你可以把块放在同一条线作为条件,这一切都在80个字符,省略大括号“。 我们拭目以待。

反对使用大括号的主要论点是,他们使用额外的行,他们需要额外的缩进。

行(几乎)是免费的,尽量减less代码中的行数不应该是一个目标。

缩进与大括号使用无关。 在你的级联“使用”例子中,我仍然认为你应该缩进他们,即使你省略了大括号。

好的,这是一个已经回答死亡的老问题。 我有一些补充。

首先,我只是说,使用的支线。 除非你正在编写程序集,否则它们只能帮助你提高可读性和可读性(对你自己和其他人来说)。 不可读的代码总是会导致错误。 如果你发现花括号使你的代码占用太多的空间,你的方法可能太长了。 任何方法的大部分或全部应该适合一个屏幕高度,如果你做的是正确的,Find(F3)是你的朋友。

现在我的补充:这是一个问题:

 if (foo) bar(); 

尝试设置一个只有在bar()将要运行时才会被触发的断点。 你可以在C#中通过将光标放在代码的后半部分来做到这一点,但这并不明显,而且有点痛苦。 在C ++中,你根本无法做到这一点。 我们的一位最高级的C ++代码开发人员坚持要把“if”语句分为两行。 我同意他的看法。

所以这样做:

 if (foo) { bar(); //It is easy to put a breakpoint here, and that is useful. } 

其中一个主要问题是当你有单线和非单线的区域时,以及与控制单元( if你有什么区别)和统计结束的分离。

例如:

 for (...) { for (...) for (...) { // a couple pages of code } // which for block is ending here? A good text editor will tell you, // but it's not obvious when you're reading the code } 

我曾经是一个“大括号是必须的”的大支持者,但是由于采用了unit testing,我发现我的unit testing可以保护大胆的语句,例如:

 if (foo) snafu(); bar(); 

通过良好的unit testing,我可以放心地省略花括号来简化语句以提高可读性(是的,这可以是主观的)。

或者,对于上面的东西,我可能会把它看成是:

 if (foo) snafu(); 

那样的话,需要添加bar()的条件的开发人员更容易识别缺less花括号,并添加它们。

I'm a strong believer in writing tidy and concise code, but I would always use curly braces. I find that they are a convenient way of quickly seeing the scope in which a particular line of code exists. There is no ambiguity, it's just explicitly set out in front of you.

Some may say it is a case of preference, but I find the logical flow of a program much easier to follow if it is internally consistent, and I don't believe that it is consistent to write one IF statement like this;

 if(x < y) x = y; else y = x; 

And another like this;

 if(x < y) { x = y; x++; } else { y = x; y++; } 

I prefer to just pick one general style and stick with it 🙂

Use some personal judgement.

 if (foo) bar(); 

is fine by itself. Unless you're really worried about morons putting in something like this later:

 if (foo) bar(); baz(); 

If you're not worried about morons, you're fine (I'm not — if they can't get basic code syntax right, this is the least of their problems)>

In exchange, it's a lot more readable.

The rest of the time:

 if (foo) { bar(); baz(); } 

Which has been my favorite as long as I can remember. 另外:

 if (foo) { bar(); baz(); } else { qux(); } 

为我工作。

Vertical space by itself isn't terribly relevant, readability is. The opening brace on a line by itself just stops the conversation for a syntactic element, until your eye moves down to the next line. Not what I like.

Let's say you have some code:

 if (foo) bar(); 

and then someone else comes along and adds:

 if (foo) snafu(); bar(); 

According to the way it's written, bar(); is now executed unconditionally. By including the curly braces, you prevent this kind of accidental error. Code should be written in such a way as to make such mistakes difficult or impossible to make. If I was doing a code review and saw the missing braces, especially spread across multiple lines, I would create a defect. In cases where it is justified, keep it on one line so that the chance of making such an error is again kept to a minimum.

Reducing lines is not really a good argument for dropping braces. If your method is too big, it should probably be refactored into smaller pieces or restructured. Doing that will no doubt increase readability more than simply taking out braces.

I always omit them when appropriate, such as in your first example. Clean, concise code I can see and understand by glancing at is easier to maintain, debug and understand than code I have to scroll through and read line by line. I think most programmers will agree with this.

It is easy for it to get out of hand if you start doing multiple nesting, if/else clauses and so on, but I think most programmers should be able to tell where to draw the line.

I see it kind of like the argument for if ( foo == 0 ) vs if ( 0 == foo ) . The latter may prevent bugs for new programmers (and maybe even occasionally for veterans), while the former is easier to quickly read and understand when you're maintaining code.

in order to keep the code with braces from taking up lots of space, I use the technique recommended in the book Code Complete :

 if (...) { foo(); bar(); } else { ... } 

Most times it is ingrained as a coding standard, whether for a company or an FOSS project.

Ultimately someone else will need to grok your code and it is a major time drain for each developer to have to figure out the specific style of the section of code they are working on.

Also, imagine that someone is going between Python and a Cish language more than once a day… In Python indenting is part of the block symantics of the language and it would be quite easy to make a mistake like the one you quote.

Err on the side of more secure – just one more bug you potentially won't have to fix.

I personally feel more secure if all of my blocks are wrapped in curlys. Even for one-liners, these are simple notations that easily prevent mistakes. It makes the code more readable in the sense that you clearly see what is in the block as not to confuse the body of the block with the following statements outside of the block.

If I have a one-liner, I typically format it as follows:

 if( some_condition ) { do_some_operation; } 

If the line is just too cumbersome then use the following:

 if( some_condition ) { do_some_operation; }