为什么每个人都告诉我编写这样的代码是一种不好的做法?
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));
您还可以获得链接usings
在一起的额外好处,而无需缩进一百万次.
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();
想要使用语言提供的更紧凑的语法是错误的吗?设计这些语言的人很聪明,我无法想象他们会提出一个总是不好用的功能.
我们是否应该编写代码,以便最低的共同分母可以理解并且使用它没有任何问题?
我还缺少另一个论点吗?
Zachary Yate.. 181
实际上,唯一真正让我感到困惑的是我在调试时,并注释掉了bar():
if(foo) // bar(); doSomethingElse();
除此之外,我倾向于使用:
if(foo) bar();
这照顾上述情况.
编辑感谢您澄清问题,我同意,我们不应该将代码写入最低的共同标准.
实际上,唯一真正让我感到困惑的是我在调试时,并注释掉了bar():
if(foo) // bar(); doSomethingElse();
除此之外,我倾向于使用:
if(foo) bar();
这照顾上述情况.
编辑感谢您澄清问题,我同意,我们不应该将代码写入最低的共同标准.
阅读速度......
除了已经提到的内容.在这一点上,我已经习惯于使用大括号和空格来解析if语句.所以我读到:
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();
如果它足够长到分成两行,请使用大括号.
我也曾经认为最好只在真正需要时使用牙箍.但不是了,主要的原因是,当你有很多代码时,它确实使它更具可读性,你可以在拥有一致的支撑样式时更快地解析代码.
除了有人在if上添加第二个语句之外,总是使用大括号的另一个好理由是这样的事情会发生:
if(a) if(b) c(); else d();
您是否注意到else子句实际上是"if(b)"的子句?你可能做过,但是你会相信任何人都熟悉这个陷阱吗?
所以,如果只是为了保持一致性,并且因为你永远不知道当其他人(它总是其他人都是愚蠢的)改变代码时会发生什么意外的事情,我总是把括号,因为它使源代码更易读,更快解析你的脑.仅对于最简单的if语句,例如if如何进行委托或类似于switch,你知道该子句永远不会扩展,我会省略括号.
我更喜欢大括号提供的清晰度.你确切地知道是什么意思,不必猜测是否有人只是愚蠢而把它们关掉(并引入了一个bug).我省略它们的唯一一次是将if和action放在同一行上.我也不经常这样做.我实际上更喜欢通过将大括号放在自己的行上而引入的空白,尽管从多年的K&R C类编程开始,以大括号结束这一行是我必须努力克服的做法,如果IDE不强制执行它我.
if (condition) action(); // ok by me if (condition) // normal/standard for me { action(); }
这并不总是被认为是一种不好的做法.在Mono项目编码准则建议不要使用大括号,如果它是没有必要的.同为GNU编码标准.我认为这与个人品味一样,与编码标准一样.
线很便宜.处理器功率很便宜.开发人员的时间非常昂贵.
作为一般规则,除非我正在开发一些绝对资源/速度关键的应用程序,否则我总是会错误地编写代码
(a)任何其他开发人员都可以轻松地遵循我正在做的事情
(b)评论可能需要它的代码的特定部分
(c)如果出现问题,易于调试
(d)如果将来需要易于修改(即添加/删除代码)
从业务角度来看,代码的速度或学术优雅是次要的.这并不是说我打算编写笨重或丑陋的代码,但这是我的优先顺序.
通过在大多数情况下省略花括号,对我来说使(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++宏的旧时代.我知道这是一个C#问题,但是编码标准通常会在没有创建标准的原因的情况下继续存在.
如果在创建宏时不是很小心,最终会导致if语句不使用{}.
#define BADLY_MADE_MACRO(x) function1(x); function2(x); if (myCondition) BADLY_MADE_MACRO(myValue)
现在,不要误解我的意思,我不是说你应该总是这样做以避免在C/C++中出现这个问题,但是由于这个原因,我不得不处理一些非常奇怪的错误.
我用同样的方式思考.
直到有一天(为什么总会有"一天"永远改变你的生活?)我们花了24到36个小时没有睡觉调试生产代码只发现有人没有把括号与搜索/替换变化相结合.
就是这样的.
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();
事实证明,该系统每天产生500 MB的日志,我们被要求停止它.调试标志是不够的,所以搜索和替换println是有序的.
仍然当应用程序进入生产时,调试标志已关闭,并且从未调用过重要的"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 if我嵌套else的地方
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(); }
只要可能,我使用三元运算符,但我从不 嵌套它们.
坦率地说,我认为:
优秀的程序员在防守程序上编程,坏程序员则不然.
由于上面有几个例子和我自己类似的与遗忘大括号有关的错误的经历,所以我学会了总是坚持不懈的方法.
其他任何事情都是选择个人风格而不是安全,这显然是糟糕的编程.
乔尔甚至在" 使错误的代码看错"中提到了这一点
一旦你因为缺少括号而得到一个bug,你就会发现丢失的括号看起来是错误的,因为你知道它是另一个bug发生的可能的地方.
总有例外情况,但我认为只有在其中一种形式时才省略大括号:
if(x == y) for(/* loop */) { //200 lines } //rampion's example: for(/* loop */) { for(/* loop */) for(/* loop */) { //several lines } }
否则,我没有问题.
我偶尔使用最底层的代码(多个使用语句),但除此之外我总是把括号放进去.我发现它使代码更清晰.显而易见的是,不仅仅是缩进,语句是块的一部分(因此可能是if等的一部分).
我见过了
if (...) foo(); bar();
臭虫咬我(或者更确切地说,"我和他的同事" -我其实没有引进的bug)一次.尽管我们当时的编码标准建议在任何地方使用括号.我花了很长时间才发现 - 因为你看到了你想要看到的东西.(这是大约10年前的事.也许我现在发现它更快.)
当然,如果你使用"支撑在行尾"它减少了额外的线路,但我个人不喜欢这种风格.(我在工作中使用它,发现它不如我预期的那么令人不愉快,但它仍然有点不愉快.)
我同意"如果你足够聪明,可以让某人付钱给你编写代码,那么你应该足够聪明,不要仅仅依靠缩进来查看代码的流程."
但是......可能会犯错误,而这一点很难调试......特别是如果你正在查看其他人的代码.
我的理念是,如果它使代码更具可读性,为什么不这样做呢?
显然你必须在某处绘制线条,比如在简洁和过于描述的变量名称之间找到快乐的媒介.但括号确实可以避免错误并提高代码的可读性.
你可以说,聪明到足以成为编码人员的人会变得足够聪明,以避免出现无括号语句的错误.但你真的可以说你从来没有像拼写错误这样简单的东西被绊倒吗?在看大型项目时,这样的细节可能会让人不知所措.
令我印象深刻的是,我在计算机编程领域的同行(你很多)并没有因为你在单行块上跳过括号时潜在错误的前景而感到沮丧.
我想这意味着我不聪明.我多次犯了这个错误.我调试了其他人的错误.因为这个问题,我已经看到了带有错误的软件(运行VS2002的机器的RDP和你的监视窗口字体会变得很糟糕).
如果我看看我所做的所有错误,可以通过改变编码风格来避免,列表很长.如果我在每种情况下都没有改变我的方法,我可能永远不会成为程序员.再说一遍,我想我不聪明.为了弥补这一点,我长期以来一直是单线模块上大括号的坚定用户.
也就是说,世界上有些事情发生了变化,使得"你在单线块上使用括号"的规则与摩西把它带到我们身上相比不那么重要:
一些流行的语言通过让计算机读取缩进来解决问题,就像程序员那样(例如Python).
我的编辑器会自动为我格式化,因此我通过缩进误导的可能性大大降低.
TDD意味着如果我引入一个bug,因为我被一个单行块搞糊涂了,我更有可能很快发现这个bug.
重构和语言表达意味着我的块更短,并且单行块的发生频率比使用时更频繁.假设有一个无情的ExtractMethod应用程序,我的整个程序中可能只有单行块.(我想知道那会是什么样的?)
实际上,在单行块上无情地重构和省略括号有一个明显的好处:当你看到大括号时,你脑海中会发出一个小小的警报,说"这里的复杂性!小心!".想象一下,如果这是常态:
if (condition) Foo(); // normal, everyday code if (condition) { // something non-trivial hapening; pay attention! Foo(); Bar(); }
我打算将我的编码约定更改为"单行块可能永远不会有大括号"或"如果你可以将块放在与条件相同的行上,并且它都适合80个字符,省略大括号".走着瞧.
在三个公约中:
if(addCurleyBraces()) bugFreeSofware.hooray();
和:
if(addCurleyBraces()) bugFreeSofware.hooray();
和(表示使用开口和右括号的任何缩进样式):
if(addCurleyBraces()) { bugFreeSofware.hooray(); }
我更喜欢最后一个:
如果所有if语句都以统一的方式编写,我会发现它更容易阅读.
它可能使软件更健壮,无bug.然而,所有现代IDE和高级文本编辑器都有很好的自动缩进功能,我认为每个人都应该使用它,只要它不会弄乱注释格式或违反团队标准(在很多情况下,可以创建自定义格式设置并与团队分享).我的观点是,如果正确完成缩进,可以减少bug引入的风险.
我更喜欢将布尔表达式和语句执行到不同的行.我希望能够为调试目的标记一行.即使我正在使用IDE,我可以在其中标记语句并继续它,它是一个交互式操作,我可能忘记了我开始调试的地方,或者至少我需要花费更多的时间来完成代码的几个步骤时间(因为我必须在调试期间每次手动标记位置).
反对使用大括号的主要论点是它们使用额外的行并且需要额外的缩进.
行(几乎)是免费的,最小化代码中的行数不应该是一个目标.
缩进与大括号的使用无关.在你的级联'使用'示例中,我仍然认为即使你省略大括号也应该缩进它们.
我非常相信编写简洁明了的代码,但我总是使用花括号.我发现它们是一种快速查看特定代码行存在范围的便捷方式.没有歧义,它只是明确地摆在你面前.
有些人可能会说这是偏好的情况,但我发现程序的逻辑流程如果内部一致则更容易遵循,而且我不认为编写这样的IF语句是一致的.
if(x < y) x = y; else y = x;
而另一个像这样;
if(x < y) { x = y; x++; } else { y = x; y++; }
我更喜欢选择一种一般风格并坚持下去:)
其中一个主要问题是,当你有一个船和非一个衬垫的区域,从控制statment分离(沿for
,if
,你有什么)和statment结束.
例如:
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 }
我曾经是"花括号是必须的!"的巨大支持者,但自从采用单元测试后,我发现我的单元测试保护了无括号语句,例如:
if (foo) snafu(); bar();
通过良好的单元测试,我可以放心地省略大括号的简单语句以提高可读性(是的,这可能是主观的).
或者,对于类似上面的内容,我可能会将其看起来像:
if (foo) snafu();
这样,需要在条件中添加bar()的开发人员更容易识别缺少花括号,并添加它们.
使用一些个人判断.
if (foo) bar();
很好.除非你真的担心傻瓜后来会这样做:
if (foo) bar(); baz();
如果你不担心蠢货,你很好(我不是 - 如果他们不能正确获得基本的代码语法,这是他们最少的问题)>
作为交换,它更具可读性.
剩下的时间:
if (foo) { bar(); baz(); }
只要我记得,这一直是我最喜欢的.另外:
if (foo) { bar(); baz(); } else { qux(); }
适合我.
垂直空间本身并不十分相关,可读性也是如此.一条直线上的左括号只会停止语法元素的对话,直到你的眼睛向下移动到下一行.不是我喜欢的.
好的,这是一个已经回答死亡的老问题.我有一些要补充的东西.
首先,我只想说使用支架.它们只能帮助提高可读性,并且可读性(对于您自己和他人!)应该在您的优先级列表中非常高,除非您正在编写程序集.总是无法读取的代码,总是会导致错误.如果你发现大括号会让你的代码占用太多空间,那么你的方法可能太长了.如果你做得对,大多数或所有方法都应该适合一个屏幕高度,而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 (foo) bar();
然后其他人出现并添加:
if (foo) snafu(); bar();
根据它的写法,bar(); 现在无条件执行.通过包含花括号,可以防止出现这种意外错误.编写代码的方式应该是难以或不可能犯这样的错误.如果我正在进行代码审查并看到缺少的大括号,特别是分布在多行中,我会创建一个缺陷.在合理的情况下,将其保持在一行,以便将出现这种错误的可能性再次保持在最低限度.
为了防止代码占用大量空间,我使用了Code Complete中推荐的技术:
if (...) { foo(); bar(); } else { ... }
减少线条并不是放弃括号的好理由.如果您的方法太大,它可能应该重构为较小的部分或重组.这样做无疑会提高可读性,而不仅仅是取出括号.
我总是在适当时省略它们,例如在你的第一个例子中.清晰,简洁的代码我可以通过浏览来查看和理解,比我必须逐行滚动和逐行读取的代码更容易维护,调试和理解.我想大多数程序员都同意这一点.
如果你开始做多个嵌套,if/else子句等等,它很容易失控,但我认为大多数程序员应该能够知道绘制线的位置.
我觉得这有点像if ( foo == 0 )
vs 的论点if ( 0 == foo )
.后者可以防止新程序员的错误(甚至可能偶尔为退伍军人),而前者在维护代码时更容易快速阅读和理解.