C#で先行ステートメントなしの{}コードブロックが許可されるのはなぜですか?


86

なぜC#は許可しないこの文のないコードブロック(例えばifelseforwhile)?

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

70
すべきはない理由はありますか?
Jamiec 2011年

30
しかし、答えが示すように、それは単に「傷つけないので、それを許してください」よりも意味があります。これがそのような質問のポイントです。
セルドン

8
+1の質問は十分に無実に聞こえますが、答えは本当に私に何か価値のあることを教えてくれました
Nicolas78 2011年

7
@Akash:理由を聞かなければ、私たちは決して良くなることはありません。
リチャード

7
@Akash:それはハイブロウのエリート主義的な態度のようです。人々は常に質問をします、そして理由を尋ねる理由がなければ、SOを持つことには意味がありません。このサイトは、人々に私たちの差し迫った問題を解決してもらうためのものではありませんが(それは起こりますが)、私たち全員がより良いプログラマーになるのに役立つ質問と回答のリポジトリを提供します。SOはなぜか尋ねるためです!:-)
リチャード

回答:


90

あなたが与える文脈では、意味はありません。コンソールに定数文字列を書き込むと、プログラムフローのどこでも同じように機能します。1

代わりに、通常はそれらを使用して、一部のローカル変数のスコープを制限します。これはここここでさらに詳しく説明さています。見てくださいジョアン・アンジェロの答えクリス・ウォリスの答えの簡単な例について。同じことがCスタイルの構文を持つ他のいくつかの言語にも当てはまると思いますが、それらがこの質問に関連するというわけではありません。


1 もちろん、まったく予想外のことConsoleをするWrite()メソッドを使って、面白くして独自のクラスを作成しようと決心しない限り。


24
Re:他の言語:通常ですが、常にではありません。JavaScriptは注目すべき例外です。特定のブロックでローカル変数を宣言しても、その変数のスコープはブロックになりません。
Eric Lippert

@EricLippert:C#では、ブロック内で変数を宣言すると、実行時の観点から変数のスコープが設定されますか?私の知る限り、変数の存続期間はスコーピングブロックによって制限されないことがよくあります。これは、ループ内の変数で最初に行われることが、out記述されたインターフェイス実装にパラメーターとして渡すことである場合、混合言語プロジェクトで観察できます。別の言語で、その実装は変数を書き込む前に変数を読み取ります。
スーパーキャット2015

また、C ++では、GCではなくRAIIがあるため、はるかに便利です。
deduplicator 2015

C ++では、try / catchブロックのように機能するため、そのスコープ内で宣言された変数とクラスは、そのスコープを離れるとスタックから飛び出します。これにより、名前の衝突を防ぎ、関数のメモリフットプリントを削減できます。また、これらの変数をコードエディターのオートコンプリートから削除します。多くの場合、try / catchブロックの方が便利です。
キット105

144

{ ... }は、少なくともローカル変数に新しいスコープを導入するという副作用があります。

私はswitchステートメントでそれらを使用して、ケースごとに異なるスコープを提供する傾向があります。このようにして、使用する最も近い場所で同じ名前のローカル変数を定義し、ケースレベルでのみ有効であることを示すことができます。



6
ケースにスコープが必要な場合は、スコープが大きすぎます。抽出方法。
ジェイバズジ2011年

20
@Jay Bazuzi、同じ名前のローカル変数を複数のケースで使用したいからといって、それらが巨大である必要があるとは限りません。あなただけにジャンプしている巨大な:) ...結論
ジョアン・アンジェロ

Great Answerバッジおめでとうございます!:)
–BoltClock

1
約@BoltClockは、おかげで、私はいくつかのより多くの質問が必要{}お越しの方金バッジを保つために:) ...
ジョアン・アンジェロ

56

これは、中括弧を使用してスコープ定義する多くのC構文言語の論理的な副作用であるため、C#の機能ではありません。

あなたの例では、中括弧はまったく効果がありませんが、次のコードでは、中括弧は変数のスコープ、したがって可視性を定義します。

これ、iが最初のブロックでスコープから外れ、次のブロックで再度定義されるために許可されます。

{
    {
        int i = 0;
    }

    {
        int i = 0;
    }
}

iがスコープから外れ、外側のスコープに表示されなくなったため、これは許可されていません。

{
    {
        int i = 0;
    }

    i = 1;
}

などなど。


1
英語のさまざまなフレーバーの括弧の命名法の違いについて読んだことがありますが、どのフレーバーが{}括弧として知られていますか?
BoltClock

良い質問!私のメンターは10年前にそれを私の脳に植えたと思います。私はおそらくそれらを「中括弧」または「中括弧」と呼ぶべきです。自分の...への各 en.wikipedia.org/wiki/...
クリス・ウォリス

10
私の単語'(' =括弧'{' =ブレース、 '[' =角括弧で
PB。

ちょっと待ってください、私はそれらを中括弧と呼びます、そしてウィキペディアはその命名を含みます。オックスフォード英語辞典では、この括弧の使用を次のように定義しています 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; 。いずれの場合も括弧ではありませんが、「中括弧」は問題ないようです。
dumbledad 2013年

IME、「中括弧」および「角括弧」。
cp.engr 2016

18

私が検討します {}は、いくつかのステートメントを含むことができるステートメントます。

ブール式の後に1つのステートメントが続くifステートメントについて考えてみます。これはうまくいくでしょう:

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

これも機能します:

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

私が間違っていなければ、これはブロックステートメントと呼ばれます。

{}他のステートメントを含めることができるため、他のを含めることもできます{}。変数のスコープは、その親{}(ブロックステートメント)によって定義されます。

私が言いたいのは、それ{}は単なるステートメントなので、ifなどを必要としないということです...


+1これは、まさにCスタイルの言語での中括弧とは何か、いわゆる「複合ステートメント」です。
Michael Ekstrand

12

C構文言語の一般的な規則は、「その間のすべてを{ }単一のステートメントとして扱う必要があり、単一のステートメントが可能なところならどこにでも移動できます」です。

  • if
  • の後forwhileまたはdo
  • コードのどこでも

すべての意図と目的のために、それは言語文法がこれを含んでいたようです:

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

つまり、「ステートメントは、(さまざまなもの)または開始中括弧で構成され、その後にステートメントリスト(1つ以上のステートメントを含む場合があります)が続き、その後に閉じ中括弧が続きます」。IE「{ }ブロックはどこでもどんなステートメントでも置き換えることができます」。コードの途中に含まれます。

{ }単一のステートメントが移動できる場所にブロックを許可しないと、実際には言語定義がより複雑になります。


誰かがこの回答を(9年後に)引き上げました。これは実際にはこの質問に対する具体的な回答ではなく、はるかに一般的な議論でした。言語やライブラリに取って代わられてしまったのかもしれませんが、とにかく楽しかったです、ありがとう。
マッシモ

1

C ++(およびJava)は、先行するステートメントなしでコードブロックを許可したためです。

C ++は、Cが許可したため、それらを許可しました。

それはすべて、ヨーロッパのプログラム言語(Modula-2ベース)の設計ではなく、米国のプログラム言語(Cベース)の設計が勝ったという事実に帰着すると言えます。

(制御ステートメントは単一のステートメントに作用します。ステートメントはグループにして新しいステートメントを作成できます)


Module2、またはModula2のことですか?
リチャードEv

確かに、これは正解です。さらに、「すべてのコンピューター言語がそうするので
Fattie 2016年


0

1なぜなら...それはステートメントのスコープ領域を維持します..または関数、これは大きなコードを操作するのに本当に便利です..

{
    {
        // 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;
    }
}

ここに画像の説明を入力してください


0

あなたは「なぜ」C#が前のステートメントなしでコードブロックを許可するのかと尋ねました。「なぜ」という質問は、「この構成の可能な利点は何でしょうか?」と解釈することもできます。

個人的には、コードブロックがローカル変数のスコープを制限することを念頭に置いて、他の開発者の可読性が大幅に向上するC#でステートメントのないコードブロックを使用しています。たとえば、次のコードスニペットについて考えてみます。これは、追加のコードブロックのおかげではるかに読みやすくなっています。

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

これは、構造レベルごとにメソッドを使用することで、よりエレガントに解決できることを認識しています。ただし、繰り返しになりますが、サンプルデータシーダーのようなものは通常迅速である必要があることに注意してください。

したがって、上記のコードは線形に実行されますが、コード構造はオブジェクトの「実際の」構造を表しているため、他の開発者が理解、維持、拡張するのが容易になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.