处理大括号汤


11

我已经在C#和VB.NET中编程了多年,但主要是在VB中编程。我正在向C#转变职业生涯,总的来说,我更喜欢C#。

我遇到的一个问题是大括号汤。在VB中,每个结构关键字都有一个匹配的close关键字,例如:

Namespace ...
    Class ...
        Function ...
            For ...
                Using ...
                    If ...
                        ...
                    End If
                    If ...
                        ...
                    End If
                End Using
            Next
        End Function
    End Class
End Namespace

用C#编写的同一代码最终很难阅读:

namespace ... {
    class ... {
        function ... {
            for ... {
                using ... {
                    if ... {
                        ...
                    }
                    if ... {
                        ...
                    }
                }
            }
            // wait... what level is this?
        }
    }
}

习惯了VB,我想知道c风格的程序员是否使用一种技术来提高可读性并确保您的代码以正确的“块”结尾。上面的示例相对容易阅读,但是有时在一段代码的结尾,我将拥有8个或更多级别的花括号,这需要我向上滚动几页才能找出哪个花括号结束了我感兴趣的代码块在。


83
我知道这听起来像是布道,也许您有一些特殊条件(因为是的,有时是必要的-幸好这种情况很少见),但通常 “ ... 8个或更多级别的花括号,需要我滚动最多几页,找出哪个花括号结束了我感兴趣的代码”,这意味着代码需要进行认真的重构和清理。
FrustratedWithFormsDesigner 2012年

7
我已经看过并且已经开始做的一件事是在花括号的结尾处,我将对此添加评论。有点像// End's using X statement
PiousVenom 2012年

14
@FrustratedWithFormsDesigner可以发现您的控制流很混乱,需要重做。就是说,我认为您对花括号的抱怨比对范围的抱怨更多,我想您只需要习惯就可以了。学习一种与您以前使用的语法大不相同的语言,肯定看起来像一会儿汤,但是实践却消失了。您只需要低调处理,直到您的大脑开始更自然地处理语法,您就会到达那里。
吉米·霍法

2
@FrustratedWithFormsDesigner-我需要在COM互操作情况下清理很多COM对象。我正在使用本文建议的技术:jake.ginnivan.net/vsto-com-interop。这很容易创建两到三层。当您将for循环,函数,类和名称空间堆叠在该循环(以及if语句)之上时,您很容易获得几层花括号。
JDB仍记得Monica

5
@TyrionLannister-这些评论可能是最快的评论,与它们所属的评论不同步...我想如果我有类似的评论,我希望它是自动生成的(显示时) -time(仅持续时间,不保留)。
Clockwork-Muse

Answers:


39

将起始大括号放在与结尾大括号相同的“等级”中,如下所示:

namespace ... 
{
    class ... 
    {
        function ... 
        {
            for ... 
            {
                using ... 
                {
                    if ... 
                    {
                        ...
                    }
                    if ... 
                    {
                        ...
                    }
                }
            }
            // It's the `function` level!
        }
    }
}

15
我同意。埃及括号使我头疼。
PiousVenom 2012年

8
此外,大多数IDE(可能)在单击大括号时会突出显示该伙伴。
StuperUser 2012年

3
@TyrionLannister:感谢您终于给我一个关于该样式的术语!除了“错位的牙套”外,我从未为他们起过好名字。
FrustratedWithFormsDesigner 2012年

3
@ Cyborgx37:您的IDE是否具有“转到匹配的括号”功能?通常绑定到一个快捷键,该快捷键会自动将光标移动到与当前突出显示的括号匹配的括号。
FrustratedWithFormsDesigner 2012年

3
得说,我不知道这如何使它变得更容易。无论哪种方式,您都只需要在大括号的缩进级别上查找屏幕,直到找到关键字为止。随着所有这些额外的行,您现在可以进一步查看。
Blorgbeard将于

14
  • 根据您的IDE:将光标放在打开/关闭括号处,它将突出显示该括号和相应的括号。
  • 折叠该块,它会向您显示打开/关闭的位置。
  • 编写较小的代码块。说真的 检出Clean Code,再也不会遇到此问题(并且具有更多可读性/可维护性的代码)。

请注意,以下是有效的c#语法,可能会帮助您解决特定情况:

using (var type = new MyDisposable1())
using (var type2 = new MyDisposable2())
{
    /* do what you will with type2 and type2 */
}

寻找单个突出显示的角色是促使我首先提出这个问题的原因。
JDB仍记得Monica

2
@ Cyborgx37:因此指向第3点。如果您的整个代码块都可以显示在屏幕上,则无需搜索。在我编写的大多数/所有类中,唯一不适合在屏幕上显示的括号是名称空间/类。
史蒂文·埃弗斯

您在第1点和第2点中提出的建议是我现在要做的...但是这要求我离开要进行编码的地方,并开始处理我的代码视图,以找出下一行的位置。第3点是良好的拍摄,但并不总是可能的,特别是如果你的代码需要几层using块(见jake.ginnivan.net/vsto-com-interop
加多宝还记得莫妮卡

@ Cyborgx37:看我的编辑。
史蒂文·埃弗斯

1
@ Cyborgx37如果您选择一种与众不同的颜色(我使用紫色背景和白色文字一段时间,IIRC),则无需寻找匹配的花括号-实际上,它对着您是SCREAMS的意思是“我在这里! ”。
CVn 2012年

5

常见的约定是在右括号后面添加注释以指示其即将关闭的结构:

if {
   ...
} // end if

while (condition) {
   ...
} // end while

等等。我自己从未热衷于这个约定,但是有些人发现它很有帮助。


16
我见过人们这样做,当他们交换/更改块的开头(将a更改while为a for,交换为if语句)时,他们几乎永远不会记得更新结束注释,这使它们变得比没有用处更糟。仅当您每次匹配的性质{发生变化时都可以强迫自己维护注释时,此约定才可能有用。
FrustratedWithFormsDesigner 2012年

是的,我已经完成了一些工作,但这是很多额外的工作(和噪音)。我希望会有更简单的方法。
JDB仍记得Monica

5
注释只应说明为什么从不做什么,也不怎么做,因为这两种代码都一样,并依靠注释来解释它们中的任何一个,这意味着代码难以阅读,这是应纠正代码而不注释的标志。
吉米·霍法

1
这使我想知道为什么没有人写了一本编辑器,显示这些评论,但实际上不包括他们在代码..
布伦丹·朗

2
@JimmyHoffa:我认为一个更好的评论规则是它们应该提供清晰度。通常,这意味着回答“为什么”,但也可能意味着其他事情。不要被教条所困扰,以至于阻止您去做一些真正有用的事情,例如,偶尔在离开括号很远的闭括号中添加注释。
布莱恩·奥克利

5

通常,当很难匹配任何样式的花括号时-这可能意味着该方法过长,应进行重构。


5

我认为您需要用牙套加固。最终,它们将成为您的第二天性,您会想知道如果没有它们,您将如何生活。

但是,请确保它们缩进适当,并遵守某些间距约定(与哪一个无关)。


一年后,这个建议成真。:)
JDB仍然记得Monica

4

我通过水平折叠名称空间和类作用域来删除2级嵌套。请注意,这些方法与屏幕的左边缘齐平。我看不出每个文件都失去2个级别的缩进的意义。

在那之后,您很少会嵌套超过4个级别。

namespace FooNameSpace {
class Foo {

public void bar()
{
    while(true)
    {
        while(true)
        {
            break;
        }
    }
}

public void fooBar()
{
    foreach(var item in FooList)
    {
        foreach(var b in item.Bars)
        {
            if(b.IsReady)
            {
                bar();
            }
            bar();
        }
        bar();
    }
}

}}//end class, namespace

我喜欢这个主意,但是Visual Studio似乎不支持它(至少在2008年。到年底我们将升级到2012年,因此希望如此)
JDB仍然记得Monica

@ Cyborgx37。我在VIM外部编辑文本,所以这不是问题。但是在Visual Studio中执行:Control + A,然后单击“减少缩进”按钮。仅对新文件执行此操作。不要打扰现有文件,因为它会破坏源代码管理中的差异比较。
mike30 2012年

在右方括号/大括号中键入将启动VS的自动格式设置,但您始终可以按CTRL + z拒绝其建议。
亚历克斯在巴黎

1

我最近决定尝试并正式确定关于流控制构造的两个规则,基本上是这样的:

  • 除了必要的代码流构造之外,您应该什么都没有
  • 您应该使代码流结构尽可能小

出于您提到并清楚知道的原因,我认为这些是遵循的好规则。您可以采用几种简单的技术来实现它们:

  • 尽快退出范围(包括循环和函数的范围)
  • 注意通过退出上述if可以缓解的其他问题,并应用我提到的范围退出技术
  • 如果if中的代码大于外部的代码,请反转条件检查
  • 当循环的大小变大以至于掩盖了该方法的其余部分时,将一个循环内的代码分解为另一个方法
  • 监视任何仅包含另一个作用域的作用域,例如,一个函数,其整个作用域由if填充,而if之外没有任何内容

在这里详细说明一些示例,这些示例说明了如果不按照这些操作操作,最终会像您所说的那样将代码放入错误的代码块中,这很不好,而且很容易在维护期间出现错误。


谢谢,可能有一个或两个我可以重构的地方。这会有所帮助,但是很难重构出几个嵌套using块。
JDB仍记得Monica 2012年

如果嵌套嵌套实现作用域,则可以内联使用@ Cyborgx37实际使用的块,请看这里stackoverflow.com/questions/1329739/…它的工作原理基本上与单行流控制构造如何(true)doSomething();一样。您还可以if(true)if(somethingElse)if(otherThings){doThis(); 去做(); doWhatever(); }和ifs嵌套,如您所愿(不要编写代码,就像对上帝的爱一样,只用这种用法,别无所求)
Jimmy Hoffa

是的,我知道使用块进行嵌套,但这仅在下面有一行的情况下才有效。在我的大多数代码中,情况并非如此。总体上还是很有帮助的……...学到了一些东西(+1)
JDB仍然记得Monica 2012年

@ Cyborgx37是的,我知道作用域嵌套仅在您没有多余位的情况下才起作用,那说明您的使用方式是否存在某种模式?如果将多余的部分移到构造函数的顶部,或者如果将其放在底部,则将其转移到构造函数中,是否可行?那是有图案的。猜测可能是因为您提出这个问题,所以您很可能经常在代码中使用嵌套来使用它们。
吉米霍法

我实际上已经开始在Factory模式实施中进行工作,该实现将COM对象包装在“ AutoCleanup”类中。然后,我using在工厂类上使用单个语句,并在处理它时自动处理所有包装的类。到目前为止,它运行良好,并且大大减少了using代码中的语句数量。
JDB仍记得Monica

1

不幸的是,这是计算中最古老的战争原因之一。可以从两方面进行合理的论证(更好的垂直房地产经济性和更容易在视觉上将左大括号与右大括号匹配的能力),但实际上,简单的源代码格式化程序将为您解决所有问题。MS Visual C#具有一个内置的,可以很好地运行。

但是请注意,如果您是团队成员,则应该遵守该团队所使用的约定,因此,您必须熟悉这两种风格,并避免因大括号风格而信服。

因此,在学习的过程中,一定要专注于使您更容易学习的风格,而在学习时却将注意力放在另一半上,您会做得很好。


1
我不确定这是默认格式程序还是ReSharper中的某种格式,但是当我以前使用C#时,我们有一个选项集可以将代码重新格式化为检入的一部分。这样,您可以在使用代码时格式化所需的代码,但是在签入时会将其重新格式化为“项目标准”。我认为我们唯一真正的格式化标准是使用空格而不是制表符。
TMN 2012年

1

使用Resharper,这将有助于推荐减少嵌套的方法。另外,请阅读鲍勃·马丁(Bob Martin)的书“ 清洁代码Clean Code)”,该书强调一个函数只能做一件事,因此每个函数只能长六行,因此您不必担心太多层次的嵌套。


1

该编辑器有一个附加组件,可以帮助您:C#Outline

该插件通过添加功能来折叠,扩展和突出显示嵌套的代码块,从而扩展了C#的VS20xx编辑器。这些功能使编辑和读取代码块的嵌套内容(如if,while等)更加容易。


0

如果您在Visual Studio中编写代码,那么还会有一个插件,向您显示所构造的每个结构的开始和结束之间的垂直点。

但是总的来说,我认为这将需要一段时间,直到您习惯了“ Curly-Braces-Soup”。(顺便说一句,我真的很喜欢这种表达。听起来有点像《大爆炸理论》中的情节名称)


0

缩进可以用两种语法告诉您您的位置。如果您单行编写VB程序或C#程序,您将很快无法分辨嵌套语法的位置。机器解析块结尾的短语或花括号,但是人类需要缩进。

块结尾短语来自打孔卡和纸带时代,那时编程的交互性和可视性要差得多。或者,实际上,根本没有互动。输入程序很困难,因此程序员需要编译器在语法分析和错误恢复方面非常聪明。

在那个过去的时代,编辑-编译-运行周期可能涉及到使用打卡机准备打孔卡,然后排队到作业提交窗口,店员将打孔卡提交给机器。以后,程序员将从另一个窗口收集输出(打印在纸上)。如果程序有错误,则输出将仅包含编译器诊断。当周转时间较长,打字所增加的成本end if,而不是仅仅)是有道理的,如果它有助于提高诊断质量,因为程序员需要正确的尽可能多的错误,可能在一个单一的迭代,以减少浪费时间的数通过作业提交窗口进行迭代。

当缺少闭合的花括号时,很难确定哪个未闭合的花括号。(编译器可能必须解析缩进,以进行有根据的猜测。)如果删除函数内的右括号,则文件的其余整个部分看起来像是该函数的一部分,从而导致出现无用的错误消息。而如果您有end function语法,则编译器可以推断出错误函数的结束位置,可以正确地恢复和解析后续函数,从而为您提供有意义的其他诊断(如果有)。

当您使用可自动缩进代码并使代码着色的可识别代码的文本编辑器时,在可以看到60或更多行的高分辨率屏幕上,这些笨拙语言的参数不再适用。您可以快速地增量编辑和重建程序,从而一次只能处理一个错误。此外,通过在屏幕上同时查看程序的大部分内容并保持适当的缩进,可以首先减少此类嵌套错误的发生。好的编程文本编辑器甚至会在您键入时标记某些语法错误。此外,有些折叠式编辑器将根据程序的语法折叠程序的各个块,从而给出程序结构的“类似大纲”的视图。

Lisp从一开始就使用括号,也许并非巧合,Lisp黑客通过构建接受小块程序(表达式)的系统,率先将编程作为一种交互式体验。

实际上,正如Python语言所说明的,您根本不需要结尾符号。该identation可以仅仅结构。即使在机器依赖于结尾符号或短语的语言中,人类也已经使用缩进来操纵代码的结构。


-1

如果您使用的是IDE,只需按Crtl+ k+ D,IDE将完成其余的工作。


哪个IDE eclipse使用ctrl-shift-i进行缩进,并使用ctrl-shift-f进行格式化
棘手的怪胎2012年

在视觉工作室签到
Jagz W 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.