2016-07-07 7 views
6

この問題で説明する動作を再現するために、以下の編集を参照してください。Cで例外を正しくスローする方法#

例外がスローされたときにC#のyield returnコンストラクトがGetStrings()メソッドを無期限に呼び出すため、次のプログラムは終了しません。

class Program 
{ 
    static void Main(string[] args) 
    { 
     // I expect the Exception to be thrown here, but it's not 
     foreach (var str in GetStrings()) 
     { 
      Console.WriteLine(str); 
     } 
    } 

    private static IEnumerable<string> GetStrings() 
    { 
     // REPEATEDLY throws this exception 
     throw new Exception(); 
     yield break; 
    } 
} 

この簡単な例では、私は明らかに代わりreturn Enumerable.Empty<string>();を使用することができ、そして問題が消えます。しかし、もっと興味深い例では、私は例外が一度スローされると期待して、メソッドが呼び出されなくなり、IEnumerableを「消費する」メソッドに例外をスローします。

この現象は発生する可能性がありますか?

EDIT:問題は私が最初に考えたものとは異なります。上のプログラムは終了せず、foreachループは無限ループのように動作します。以下のプログラムは終了し、例外がコンソールに表示されます。

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      foreach (var str in GetStrings()) 
      { 
       Console.WriteLine(str); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 
    } 

    private static IEnumerable<string> GetStrings() 
    { 
     throw new Exception(); 
     yield break; 
    } 
} 

はなぜtry ... catchブロックは、この場合の違いを作るのですか?これは私にとって非常に奇妙なようです。 @AndrewKilburnに感謝してくれてありがとうございました。

EDIT#2: コマンドプロンプトから、プログラムはどちらの場合も同じことを実行します。 Visual Studio Enterprise 2015 Update 2では、DebugまたはReleaseでコンパイルしても、上記の動作が表示されます。 try ... catchでは、プログラムは例外で終了し、Visual Studioがプログラムを終了することはありません。

EDIT#3:修正済み 私の場合、問題は@MartinBrownの回答によって解決されました。 [デバッグ]> [オプション]> [デバッグ]> [一般]> [未処理の例外でコールスタックをアンワインド]のVisual Studioのオプションをオフにすると、この問題は解決しません。ボックスにもう一度チェックを入れると、問題が戻ってきます。トライキャッチでそれを置く

+0

私はそれを試してみると、一度だけスローします。 'foreach'を' try catch'でラップする場合、例外は一度だけキャッチされ、プログラムは終了します。私はそれを正しく理解しましたか? – Szer

+0

うーん、私はその行動を見ていないよ。私はもう一度確認してみましょう。私が見ている動作は例外がスローされ、何とかシーンの後ろで捕まえられ、 'foreach'ループが無限ループのように振る舞います。 –

+0

@Szer私の編集を参照してください、 'try' ...' catch'ブロックは、foreachループが無限ループとして機能するかどうかを変えるようです。あなたには意味がありますか? –

答えて

5

ここで見られる動作は、コードの誤りではありません。むしろ、それはVisual Studioデバッガの副作用です。これは、Visual Studioでスタックの巻き戻しをオフにすることで解決できます。 Visual StudioのオプションDebugging/Generalに行き、 "未処理の例外でコールスタックをアンワインド"を選択解除してみてください。次に、コードを再度実行します。

コードが完全に処理されない例外に遭遇した場合、Visual Studioは例外を引き起こしたコード内の行の直前に呼び出しスタックを巻き戻します。これにより、編集したコードでコードを編集して実行を継続できるようになります。

ここで見られる問題は、デバッガで実行を再開するときに次の実行する行が例外を発生させただけなので、無限ループのように見えます。デバッガの外では、コールスタックは未処理の例外で完全に解かれ、デバッガと同じループが発生することはありません。

このスタック巻き戻し機能は、設定でオフにすることができます。デフォルトで有効になっています。しかし、これをオフにすると、コードを編集できず、最初にスタックを巻き戻すことなく続行できなくなります。ただし、これはコールスタックウィンドウから行うか、単にException Assistantから 'Enable Editing'を選択するだけで簡単に実行できます。

System.Exception: EnumerableCount: 1 
    at {insert stack trace here} 

実行フローがGetStringsに入る()メソッド最初の反復のために、例外がスローされ、main()メソッドでキャッチ:

+0

これで問題が解決しました。理由は何ですか? –

+0

悲しいことに、私が実際にしていることは、少し限られています。あなたがこれを理解してくれたら教えてください。 –

+0

@JohnCarpenter [ここ](https://blogs.msdn.microsoft.com/saraford/2008/08/08/did-you-know-what-unwinding-the-call-stack-on-unhandled-exceptions-does -277 /)に機能が記述されています。 (あなたはコメントで説明を見つけることができます) –

0
class Program { 
     static void Main(string[] args) { 
      try { 
       foreach (var item in GetStrings()) { 
        Console.WriteLine(); 
       } 
      } 
      catch (Exception ex) { 

     } 
    } 
    private static IEnumerable<string> GetStrings() { 
     // REPEATEDLY throws this exception 
     throw new Exception(); 
     yield break; 
    } 
} 

抜け出すと、あなたが

+0

残念ながら、 'Main'メソッドでは例外が全くスローされないので、これはうまくいきません。 –

+0

@JohnCarpenter Worksはうまく動作します.. –

+0

これは面白いです...試しにキャッチすると、プログラムの動作が異なります。 'try'なしで...' catch'はプログラムがあなたのために終わるのですか? –

0

次のプログラムは、偽です

終わることは決してありませんやりたいし、それが発生します。プログラムはすぐに終了する予定です。

例外がスローされたときに、C#のyield yield構造体がGetStrings()メソッドを無期限に呼び出すためです。

これは誤りです。それはまったくこれをしません。

私は例外が、その後呼び出されるメソッドの停止があるとIEnumerable「浪費」だ方法で例外をスローし、一度投げられることを期待したいです。 起こるん正確に何

この現象は発生する可能性がありますか?

すでに提供されているコードを使用してください。

+0

それはそうではないことが判明しました。どうやらVisual Studioでは動作が違っていたようです。または少なくとも異なって現れた。 :) –

0
class Program 
{ 
    public static int EnumerableCount; 

    static void Main(string[] args) 
    { 
     EnumerableCount = 0; 
     try 
     { 
      foreach (var str in GetStrings()) 
      { 
       Console.WriteLine(str); 
       Console.Read(); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
      Console.Read(); 
     } 
    } 

    private static IEnumerable<string> GetStrings() 
    { 
     EnumerableCount++; 
     var errorMessage = string.Format("EnumerableCount: {0}", EnumerableCount); 
     throw new Exception(errorMessage); 
     yield break; 
    } 
} 

は、次の出力があります。 enterを押すと、プログラムは終了します。

Main()メソッドでtry catchを削除すると、例外が処理されなくなります。出力は次のようになります。

Unhandled Exception: System.Exception: EnumerableCount: 1 
    at {insert stack trace here} 

プログラムがクラッシュします。

関連する問題