34

次のコード行でコンパイラ警告が作成されないのはなぜですか?

void Main()
{
  throw new Exception();
  throw new Exception();
}

私が見ているように、コンパイラは2番目のスロー例外に到達できないことを通知する必要があります。

4

3 に答える 3

38

これは明らかにコンパイラのバグであり、C#3.0で導入されました。到達可能性チェッカーを大幅にリファクタリングしたちょうどその頃です。これはおそらく私の悪いことです、ごめんなさい。

バグは完全に無害です。基本的に、警告レポーターのケースを忘れてしまいました。到達可能性情報を正しく生成します。他の人が指摘しているように、codegenの前に到達不能コードを正しく削除します。

バグは、警告ジェネレーターの欠落しているケースにすぎません。そこにはトリッキーなコードがいくつかあり、コードの大部分に到達できなくなったときに無数の警告が報告されないようにしています。コンパイラには、無条件のgoto( "goto"、 "break"、 "continue")、条件付きのgoto( "if"、 "while"など)、try-catch-finally(同等のフォームを含む)に関する警告を具体的に報告するためのコードがあります。 try-catch-finally、lockやusingのように)、blocks、returns(yieldreturnとregularreturn)、ローカル宣言、ラベル付きステートメント、スイッチ、および式ステートメント。

そのリストに「throwstatements」が表示されていますか?私でもない。それは私たちがそれを忘れたからです。

ご迷惑をおかけして申し訳ございません。QAにメモを送信し、言語の将来のバージョンでこれを修正します。

これを私の注意を引いてくれてありがとう。

于 2011-06-16T16:30:00.420 に答える
7

コンパイラに警告/エラーが発生する可能性がありますが、残念ながら発生しません。ただし、ILコードを見ると、最初の例外のみが考慮されます。connect.microsoft.comにログインして、見たいものとしてこれを上げることができます。

以下のコードをILDasmする場合

static void Main(string[] args)
        {
            Console.Write("Line 1");
           throw new Exception(); 
           throw new Exception();
           Console.Write("Line 4");
        }

あなたはこれを手に入れるでしょう

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       18 (0x12)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Line 1"
  IL_0006:  call       void [mscorlib]System.Console::Write(string)
  IL_000b:  nop
  IL_000c:  newobj     instance void [mscorlib]System.Exception::.ctor()
  IL_0011:  throw
} // end of method Program::Main

最初のExceptionオブジェクトの後、他に何もILに変換されません。

于 2011-06-16T13:00:22.503 に答える
3

このバグ(Lippertが上記で呼んでいるように)は、いくつかの奇妙な結果をもたらします。もちろん、このようなコードでもコンパイル時の警告は表示されません。

static int Main()
{
  return 0;

  throw new Exception("Can you reach me?");
}

あなたが創造的であるならば、あなたはまだthrowステートメントに(無関係の)警告を誘発させることができます。この奇妙な例では、「緑」に到達できないという理由だけで、コードは警告を生成します。

static int Main()
{
  return 0;

  throw new Exception(((Func<string>)(() => { if (2 == 2) { return "yellow"; } return "green"; }))());
}

(コードはラムダからデリゲートインスタンスを作成し、デリゲートを呼び出すだけです)。

しかし、この例はより単純で、より悪いように見えます。

static int Main()
{
  int neverAssigned;

  return 0;

  throw new Exception(neverAssigned.ToString());
}

この最後のコードサンプルも警告なしでコンパイルされます!neverAssigned「使用」には到達できないため、「使用」に問題はありません。ただし、割り当てられていない(そして「実際に」読み取られていない)ローカル変数についての警告も表示されません。繰り返しになりますが、警告はまったくありません。これは非常に間違っているようです。

この動作は、Visual C#の将来のバージョンで変更されるのでしょうか。それを変更すると、以前はなかった警告が表示されます(私の意見ではこれに値します)。

追加:この動作は、Visual Studio 2015のRoslynベースのC#6.0コンパイラでは変更されていないようです。

于 2012-08-15T19:33:54.563 に答える