【问题标题】:Why does C# allow {} code blocks without a preceding statement?为什么 C# 允许 {} 代码块没有前面的语句?
【发布时间】:2011-05-26 10:06:30
【问题描述】:

为什么 C# 允许代码块没有前面的语句(例如 ifelseforwhile)?

void Main()
{
    {   // any sense in this?
        Console.Write("foo");
    }
}

【问题讨论】:

  • 有什么理由不应该
  • 但正如答案所显示的那样,它的意义不仅仅是“没有伤害,所以就让它吧”。这是提出此类问题的重点。
  • +1 问题听起来很天真,但答案确实教会了我一些有价值的东西
  • @Akash:不问为什么,我们永远不会变得更好。
  • @Akash:这似乎是一种高尚的精英态度。人们总是有疑问,如果没有理由问为什么,那么有 SO 就没有意义了。这个网站不是为了让人们解决我们眼前的问题(尽管确实会发生),而是为了提供一个问题和答案的存储库,这将帮助我们成为更好的程序员。所以是问为什么! :-)

标签: c# syntax language-design


【解决方案1】:

{ ... } 至少具有为局部变量引入新作用域的副作用。

我倾向于在switch 语句中使用它们来为每种情况提供不同的范围,这样我就可以在它们使用的最近的可能位置定义具有相同名称的局部变量,并且还表示它们只是在案例级别有效。

【讨论】:

  • 如果您的情况下需要范围,它们太大了!提取方法。
  • @Jay Bazuzi,仅仅因为我想在不止一种情况下拥有一个同名的局部变量并不意味着它们必须很大。你只是跳到 huge 结论... :)
  • 恭喜您获得“最佳答案”徽章! :)
  • @BoltClock,谢谢,我只是需要更多关于{} 的问题来保持这些金徽章的出现...... :)
【解决方案2】:

在你给出的上下文中,没有任何意义。将常量字符串写入控制台在程序流中的任何地方都将以相同的方式工作。1

相反,您通常使用它们来限制某些局部变量的范围。这将进一步阐述herehere。查看João Angelo’s answerChris Wallis’s answer 的简要示例。我相信这同样适用于其他一些具有 C 风格语法的语言,尽管它们与这个问题无关。


1当然,除非您决定尝试变得有趣并创建自己的 Console 类,并使用 Write() 方法完成一些完全出乎意料的事情。

【讨论】:

  • 回复:其他语言:通常,但并非总是如此。 JavaScript 是一个明显的例外。在特定块中声明局部变量不会将该变量的范围限定为该块。
  • @EricLippert:在 C# 中,从运行时的角度来看,在块中声明变量是否会导致变量的作用域?据我所知,变量的生命周期通常不受范围块的限制,如果在循环中对变量做的第一件事是将其作为out 参数传递给用另一种语言编写的接口实现,并且该实现在写入之前读取变量。
  • 而在 C++ 中,由于 RAII 而不是 GC,它的用处要大得多。
  • 在 C++ 中,它的行为很像 try/catch 块,因此当您离开该范围时,在该范围内声明的变量和类会从堆栈中弹出。这有助于防止名称冲突并减少函数的内存占用。它还会从代码编辑器的自动完成中删除这些变量。我经常发现 try/catch 块更有用。
【解决方案3】:

与其说它是 C# 的一个特性,不如说它是许多使用大括号定义范围的 C 语法语言的逻辑副作用。

在您的示例中,大括号根本没有任何作用,但在以下代码中,它们定义了变量的范围,从而定义了变量的可见性:

这个是允许的,因为 i 超出了第一个块的范围,并在下一个块中再次定义:

{
    {
        int i = 0;
    }

    {
        int i = 0;
    }
}

这个不允许,因为 i 已经超出范围,在外部范围中不再可见:

{
    {
        int i = 0;
    }

    i = 1;
}

等等等等。

【讨论】:

  • 我读过各种英语中括号命名法的差异,但{} 被称为括号?
  • 好问题!我猜我的一位导师十年前就将它植入了我的大脑。我可能应该称它们为“大括号”或“大括号”。每个人都有自己的...en.wikipedia.org/wiki/…
  • 在我的词汇中 '(' = 括号,'{' = 大括号,'[' = 方括号
  • 等一下,我会称它们为大括号,维基百科包含该命名。牛津英语词典将这种括号的用法定义为:One of two marks of the form [ ] or ( ), and in mathematical use also {}, used for enclosing a word or number of words, a portion of a mathematical formula, or the like, so as to separate it from the context; 在任何情况下它们都不是括号,但“大括号”似乎没问题。
  • 输入法,“花括号”和“方括号”。
【解决方案4】:

我认为{} 是一个可以包含多个语句的语句。

考虑一个存在于布尔表达式之外的 if 语句,后跟 一个 语句。 这会起作用:

if (true) Console.Write("FooBar");

这也可以:

if (true)
{
  Console.Write("Foo");
  Console.Write("Bar");
}

如果我没记错的话,这叫做块语句。

由于{} 可以包含其他语句,它也可以包含其他{}。 变量的范围由它的父级{}(块语句)定义。

我想说的是,{} 只是一个声明,所以它不需要 if 或其他...

【讨论】:

  • +1 这正是 C 风格语言中的大括号——所谓的“复合语句”。
【解决方案5】:

C 语法语言的一般规则是“{ } 之间的任何内容都应该被视为单个语句,并且它可以放在单个语句可以到达的任何地方”:

  • if 之后。
  • forwhiledo 之后。
  • 代码中的任何地方

出于所有意图和目的,就像语言语法中包含的那样:

     <statement> :== <definition of valid statement> | "{" <statement-list> "}"
<statement-list> :== <statement> | <statement-list> <statement>

也就是说,“一个语句可以由(各种事物)或一个左大括号组成,后跟一个语句列表(可能包括一个或多个语句),然后是一个右大括号”。 IE。 “{ } 块可以在任何地方替换任何语句”。包括在代码中间。

不允许{ } 块在单个语句可以执行的任何地方实际上会使语言定义更复杂

【讨论】:

  • 有人刚刚提高了这个答案(9 年后),这实际上并不是对这个问题的具体答案,而是更笼统的讨论。它很可能已被语言和库所取代。但无论如何,这很高兴,谢谢。
【解决方案6】:

因为 C++(和 java)允许没有前面语句的代码块。

C++ 允许它们,因为 C 允许。

您可以说这一切都归结为美国程序语言(基于 C)设计胜过欧洲程序语言(基于Modula-2)设计。

(控制语句作用于单个语句,语句可以分组创建新语句)

【讨论】:

  • 你是指Module2,还是Modula2?
  • 确实,这是正确的答案。此外,我只想回答 “因为每种计算机语言都可以。”
【解决方案7】:
// if (a == b)
// if (a != b)
{
    // do something
}

【讨论】:

    【解决方案8】:

    1Because...它维护了 语句..或函数,这对于鬃毛大代码非常有用..

    {
        {
            // Here this 'i' is we can use for this scope only and out side of this scope we can't get this 'i' variable.
    
            int i = 0;
        }
    
        {
            int i = 0;
        }
    }
    

    【讨论】:

      【解决方案9】:

      您问“为什么”C# 允许代码块没有前面的语句。 “为什么”这个问题也可以解释为“这种结构有什么可能的好处?”

      就我个人而言,我在 C# 中使用无语句代码块,这大大提高了其他开发人员的可读性,同时记住代码块限制了局部变量的范围。例如,考虑以下代码 sn-p,由于额外的代码块,它更容易阅读:

      OrgUnit world = new OrgUnit() { Name = "World" };
      {
          OrgUnit europe = new OrgUnit() { Name = "Europe" };
          world.SubUnits.Add(europe);
          {
              OrgUnit germany = new OrgUnit() { Name = "Germany" };
              europe.SubUnits.Add(germany);
      
              //...etc.
          }
      }
      //...commit structure to DB here
      

      我知道这可以通过对每个结构级别使用方法来更优雅地解决。但话又说回来,请记住,样本数据播种器之类的东西通常需要很快。

      因此,即使上面的代码是线性执行的,代码结构也代表了对象的“真实世界”结构,从而使其他开发人员更容易理解、维护和扩展。

      【讨论】:

        猜你喜欢
        • 2014-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-05
        • 2021-05-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多