web-dev-qa-db-ja.com

なぜステートメント(j ++)でしたか。禁止?

次のコードは間違っています(参照してください onideone ):

public class Test
{
    public static void Main()
    {
        int j = 5;
        (j++);      // if we remove the "(" and ")" then this compiles fine.
    }
}

エラーCS0201:割り当て、呼び出し、インクリメント、デクリメント、待機、および新しいオブジェクト式のみがステートメントとして使用できます

  1. 括弧を削除するとコードがコンパイルされるのはなぜですか?
  2. なぜ括弧でコンパイルしないのですか?
  3. なぜC#はそのように設計されたのですか?
169
user10607

深い洞察に感謝します。

頑張ります。

他の答えが指摘したように、ここで起こっているのは、expressionstatementとして使用されていることをコンパイラが検出していることです。 C、JavaScript、その他多くの言語では、式をステートメントとして使用することは完全に合法です。 2 + 2;はこれらの言語では有効ですが、これは効果のないステートメントです。一部の式はその値に対してのみ有用であり、一部の式は副作用(void戻りメソッドの呼び出しなど)に対してのみ有用であり、一部の式は残念ながら両方に有用です。 (増分のように。)

ポイント:式だけで構成されるステートメントは、間違いなくエラーです。ただし、これらの式は、通常、値よりも副作用に対してより有用であると考えられています。 C#の設計者は、一般的に副作用と考えられている式を許可し、通常はその値に役立つと考えられているものを許可しないことで、妥協点を見つけたいと考えました。 C#1.0で特定した一連の式は、インクリメント、デクリメント、メソッド呼び出し、割り当て、そして議論の余地のあるコンストラクター呼び出しでした。


ASIDE:通常、オブジェクト構築は、構築の副作用ではなく、生成する値に使用されると考えられます。私の意見では、new Foo();を許可することはちょっとした機能不全です。特に、セキュリティの欠陥を引き起こした実世界のコードでこのパターンを見てきました。

catch(FooException ex) { new BarException(ex); } 

コードが複雑な場合、この欠陥を見つけるのは驚くほど困難です。


したがって、コンパイラは、そのリストにない式で構成されるすべてのステートメントを検出するように動作します。特に、括弧で囲まれた式は、括弧で囲まれた式として識別されます。これらは「ステートメント式として許可」のリストにないため、許可されません。

これらはすべて、C#言語の設計原則に基づいています。 (x++);と入力した場合、おそらく何か間違ったことをしていました。これは、おそらくM(x++);の誤植か何かにすぎません。 C#コンパイラチームの態度は「この作業を行うための何らかの方法を考え出すことはできますか?」ではありません。C#コンパイラチームの態度は「もっともらしいコードが間違いのように見える場合は、開発者にお知らせしましょう)。 C#開発者はそのような態度を好みます。

さて、実際には、C#の仕様doesが暗黙的であるか、括弧が許可されていないことを明確に述べているが、C#コンパイラーはそれらを許可しているという奇妙なケースがいくつかあります。これらのほとんどすべての場合、指定された動作と許可された動作の間のわずかな矛盾は完全に無害なので、コンパイラ作成者はこれらの小さなバグを修正したことはありません。あなたはそれらについてここで読むことができます:

return myVarとreturn(myVar)に違いはありますか?

220
Eric Lippert

C#言語仕様

式を評価するには、式ステートメントを使用します。ステートメントとして使用できる式には、メソッド呼び出し、new演算子を使用したオブジェクト割り当て、=および複合代入演算子を使用した割り当て、++および-演算子を使用したインクリメントおよびデクリメント操作、await式が含まれます。

文を括弧で囲むと、いわゆる括弧付き式が作成されます。仕様から:

Parenthesized-expressionは、括弧で囲まれた式で構成されます。 ...括弧内の式は、括弧内の式を評価することによって評価されます。括弧内の式が名前空間または型を示す場合、コンパイル時エラーが発生します。それ以外の場合、括弧で囲まれた式の結果は、含まれている式の評価の結果です。

括弧で囲まれた式は有効な式ステートメントとしてリストされていないため、仕様によると有効なステートメントではありません。デザイナーがこのように選択した理由は誰でも推測しますが、ステートメント全体がかっこに含まれている場合、かっこは役に立たないためです:stmt(stmt)はまったく同じです。

46
Frank Bryce

エラーメッセージが示すように、i++を囲む括弧が式を作成/定義しているためです。簡単な式はステートメントとして使用できません。

言語がこのように設計されたのはなぜですか?誤解を招く表現をステートメントとして持ち、コードを持っているような副作用を引き起こさないバグを防ぐため

int j = 5;
j+1; 

2行目は効果がありません(ただし、気付いていないかもしれません)。しかし、コンパイラがそれを削除する代わりに(コードが必要ないため)、それを削除するように明示的に要求します(したがって、あなたは気付くかエラーになるでしょう)OR何かを入力し忘れた場合に修正します。

編集

c#の括弧(キャストや関数呼び出しなどの他の用途以外)を使用して式をグループ化し、単一の式を返します(サブ式の作成)。

そのレベルのコードでは、文のみが許可されます。

j++; is a valid statement because it produces side effects

しかし、ブレーキをかけたものを使用することで、表現としてそれを変えています

myTempExpression = (j++)

この

myTempExpression;

コンパイラーは式が副作用であることを保証できないため、有効ではありません(停止問題が発生しない限り)。

19
CaldasGSM