将大括号用于变量范围的目的是错误的吗?

Posted

技术标签:

【中文标题】将大括号用于变量范围的目的是错误的吗?【英文标题】:Is it wrong to use braces for variable scope purposes? 【发布时间】:2011-03-12 11:42:54 【问题描述】:

我有时会使用大括号来隔离代码块,以避免以后错误地使用变量。例如,当我将多个SqlCommands 放在同一个方法中时,我经常复制粘贴代码块,最后混合名称并执行两次某些命令。添加大括号有助于避免这种情况,因为在错误的地方使用错误的SqlCommand 会导致错误。这是一个插图:

Collection<string> existingCategories = new Collection<string>();

// Here a beginning of a block

    SqlCommand getCategories = new SqlCommand("select Title from Movie.Category where SourceId = @sourceId", sqlConnection, sqlTransaction);
    getCategories.Parameters.AddWithValue("@sourceId", sourceId);
    using (SqlDataReader categoriesReader = getCategories.ExecuteReader(System.Data.CommandBehavior.SingleResult))
    
        while (categoriesReader.Read())
        
            existingCategories.Add(categoriesReader["Title"].ToString());
        
    


if (!existingCategories.Contains(newCategory))

    SqlCommand addCategory = new SqlCommand("insert into Movie.Category (SourceId, Title) values (@sourceId, @title)", sqlConnection, sqlTransaction);

    // Now try to make a mistake and write/copy-paste getCategories instead of addCategory. It will not compile.
    addCategory.Parameters.AddWithValue("@sourceId", sourceId);
    addCategory.Parameters.AddWithValue("@title", newCategory);
    addCategory.ExecuteNonQuery();

现在,StyleCop 会在每次块跟随空行时显示警告。另一方面,不放空行会使代码更难理解。

// Something like:
Collection<string> existingCategories = new Collection<string>();

    // Code here


// can be understood as (is it easy to notice that semicolon is missing?):
Collection<string> existingCategories = new Collection<string>()

    // Code here

所以,

    使用大括号创建代码块只是为了变量作用域有有什么问题吗?

    如果没问题,如何在不违反 StyleCop 规则的情况下使其更具可读性?

【问题讨论】:

这些被称为匿名块。相关:***.com/questions/85282/… 和 ***.com/questions/500006/… 【参考方案1】:

阻塞代码本身并没有错,但你需要考虑你为什么要这样做。

如果您要复制和粘贴代码,您可能会遇到这样的情况:您应该重构代码并生成重复调用的函数,而不是重复执行相似但不同的代码块。

【讨论】:

我同意。技术上没有任何问题。这是一种风格上的抱怨,并且可能是长功能的警告信号,确实应该将其拆分为更小、更易于管理的部分。 “您可能处于应该重构代码的情况”:这与复制/粘贴大块代码无关。如果两个变量具有相似的名称(sqlGetProductFromTablesqlAddProductToTable),则在使用 Intellisense 时会出现同样的问题。变量名很容易打错,而且对于编译器来说,代码是完全正确的,它会执行,但会产生一些意想不到的东西。 @MainMa:重用块并不是重构的唯一原因。一个巨大的方法可以单独成为将其分解为更小部分的充分理由。【参考方案2】:

使用using 语句代替裸括号块。

这将避免警告,并让您的代码在资源方面更有效率。

从更大的角度来看,您应该考虑将此方法拆分为更小的方法。使用一个SqlCommand 后跟另一个通常最好通过调用一个方法然后另一个方法来完成。然后,每种方法都将使用自己的本地SqlCommand

【讨论】:

我相信 using() 需要一个 IDisposable,在这种情况下他可能没有。 这适用于这种特殊情况(因为SqlCommand 实现了IDisposable,但不能解决他的一般情况。 这很难看,但你不能用do ... while(false); 代替吗?不过,关闭警告可能是一个更好的解决方案。 我同意。把这些代码块变成它们自己的方法并调用它们。 OP 中的块看起来有点奇怪,如果我遇到该代码,我会重构它。 @Joel 你说得对,在这种情况下没问题,但正如亚当所说,它没有解决一般情况,这就是我所指的。【参考方案3】:

我认为纯粹使用大括号来界定范围没有什么问题——它有时会非常有用。

举个例子——我曾经遇到过一个分析库,它使用Profile 对象来对代码段进行计时。它们通过测量从创建到销毁的时间来工作,因此通过在堆栈上创建然后在超出范围时被销毁,从而测量在该特定范围内花费的时间,效果最好。如果您想为本身没有自己的范围的事物计时,那么添加额外的大括号来定义该范围可能是最好的方法。

至于可读性,我可以理解为什么 StyleCop 不喜欢它,但是任何有 C/C++/Java/C#/... 经验的人都知道大括号对定义了一个范围,而且应该相当明显这就是你想要做的。

【讨论】:

【参考方案4】:

我认为这样的积木是个好主意,我经常使用它们。当您需要将太小而无法提取到方法中的代码块分开时,或者当方法由几个代码块组成看起来彼此相似,但逻辑不同时,它很有用。它允许为变量赋予相同的名称而不会发生命名冲突,这使得方法体更具可读性。

顺便说一句,我认为 StyleCop 的默认规则集包含更多规则,权宜之计值得商榷。

【讨论】:

【参考方案5】:

我不得不说,如果我要在你之后处理这段代码,我会因为你使用范围而有点反感。它不是,afaik,常见的做法。

我认为你这样做是一种气味。我认为更好的做法是将每个范围分解为具有完全描述性名称和文档的自己的方法。

【讨论】:

以上是关于将大括号用于变量范围的目的是错误的吗?的主要内容,如果未能解决你的问题,请参考以下文章

es6解构中括号前加分号

在大括号扩展范围中使用变量馈送到 for 循环

VS 设置括号背景色

c语言问题咨询 do while 大括号的使用问题

详解shell脚本括号区别--$()$「 」$「 」 $(()) 「 」 「[ 」]

刀片引擎:打印三重花括号