web-dev-qa-db-ja.com

ifステートメント内で変数を定義できないのはなぜですか?

この質問は以前に回答されたかもしれませんが、Word ifが頻繁に発生するため、見つけるのが困難です。

この例は意味をなしません(式は常に真です)が、私の質問を示しています。

このコードが有効な理由:

StringBuilder sb;
if ((sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

しかし、このコードはそうではありません:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

whileステートメントに関する同様の質問を見つけました。受け入れられた答えは、whileステートメントでは、変数が各ループで定義されることを意味すると述べています。しかし、私のifステートメントの例では、そうではありません。

では、これが許可されていない理由は何ですか?

44
comecme

これは、C#言語仕様のセクション8.5.1が原因です。状態:

さらに、ローカル変数宣言の変数初期化子は、宣言の直後に挿入される割り当てステートメントに正確に対応します。

これは基本的に次のことを意味します:

StringBuilder sb = new StringBuilder("test")

実際には、次とまったく同じことを実行しています。

StringBuilder sb; sb = new StringBuilder("test")

そのため、割り当ては単一の式ではなく、local-variable-declaratorであるステートメントであるため、!= nullに対するチェックの戻り値はなくなりました。識別子で構成されます式が後に続く

言語仕様では、この例を次のように示しています。

void F() {
   int x = 1, y, z = x * 2;
}

以下とまったく同じです。

void F() {
   int x; x = 1;
   int y;
   int z; z = x * 2;
}
37
Reed Copsey

C#7のパターンマッチング を試してください。

あなたの例を使用して:

if (new StringBuilder("test") is var sb && sb != null) {
    Console.WriteLine(sb);
}
19
Jecoms

これは、ステートメントと式の違いに関係しています。式には値がありますが、ステートメントにはありません。

例を使用して、次の分類に注意してください。

StringBuilder sb; // statement

sb = new StringBuilder("test") // expression

StringBuilder sb = new StringBuilder("test"); // statement

中央部分のみが式であることに注意してください。

次に、条件ステートメントに移ります。等しくない演算子を使用するための構文は次のとおりです。

expression != expression

したがって、!=の両側には、実際に値を持つものが必要です(これは理にかなっています)。エルゴ、あなたは演算子の両側にステートメントを持つことはできません。これが、コードの1つのバージョンが機能する一方で、他のバージョンが機能しない理由です。

の代わりに:

if ((StringBuilder sb = new StringBuilder("test")) != null) {
    Console.WriteLine(sb);
}

次のように書くこともできます:

for (StringBuilder sb = new StringBuilder("test"); sb != null; sb = null) {
    Console.WriteLine(sb);
}

このforループは、変数がnullでない場合に1回実行されます。ループの最後で、一時変数はnullに設定されます。その後、ループ条件は偽と評価され、閉じ括弧が実行された後、次のステートメントが続行されます。 ifステートメントが元々意図していた通り。

3
user809316