2012年12月13日木曜日

try、catch、finally と ハンドルされていない例外

例外処理をするには、try-catch-finally 構文を使いますが、各ブロックの中で、return や 例外が発生したときに、どのような処理フローになるのかを再確認します。

4つのパターンを試しています。
1.tryの中でreturn
2.tryの中で例外発生
3.tryの中で例外発生かつcatchの中でreturn
4.tryの中で例外発生かつcatchの中で例外発生

各パターンをボタンの Click イベントハンドラに記述します。
try-catch-finally の各ブロックを通ったかどうかを TextBox に表示して確認します。



<Window x:Class="TryCatchTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="250" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0">
            <Button Click="Button_Click_1">1.tryの中でreturn</Button>
            <Button Click="Button_Click_2">2.tryの中で例外発生</Button>
            <Button Click="Button_Click_3">3.tryの中で例外発生かつcatchの中でreturn</Button>
            <Button Click="Button_Click_4">4.tryの中で例外発生かつcatchの中で例外発生</Button>
        </StackPanel>
        <TextBox Grid.Row="1" Name="textBox1" />
    </Grid>
</Window>

1.tryの中でreturn

tryブロックの中で return しても、finally は必ず処理されます。

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            this.textBox1.Clear();
            this.textBox1.Text += "## Start \n";
            try
            {
                this.textBox1.Text += "try1 \n";
                return;
            }
            catch
            {
                this.textBox1.Text += "catch1 \n";
            }
            finally
            {
                this.textBox1.Text += "finally1 \n";
            }
            this.textBox1.Text += "## Last \n";
        }

2.tryの中で例外発生

catch 、finally の順に 処理されます。

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            this.textBox1.Clear();
            this.textBox1.Text += "## Start \n";
            try
            {
                this.textBox1.Text += "try1 \n";
                throw new Exception();
            }
            catch
            {
                this.textBox1.Text += "catch1 \n";
            }
            finally
            {
                this.textBox1.Text += "finally1 \n";
            }
            this.textBox1.Text += "## Last \n";
        }


3.tryの中で例外発生かつcatchの中でreturn

catchの中でreturn しても、finally は必ず処理されます。
finallyブロックを出たあとにコードを書いても、「到達できないコード」と警告が出るので、削除してます。


        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            this.textBox1.Clear();
            this.textBox1.Text += "## Start \n";
            try
            {
                this.textBox1.Text += "try1 \n";
                throw new Exception();
            }
            catch
            {
                this.textBox1.Text += "catch1 \n";
                return;
            }
            finally
            {
                this.textBox1.Text += "finally1 \n";
            }
        }

4.tryの中で例外発生かつcatchの中で例外発生

catch の中で発生させた例外は、ハンドルされていない例外なので、アプリケーションが動作を停止します。(アプリケーションエラー)



        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
            this.textBox1.Clear();
            this.textBox1.Text += "## Start \n";
            try
            {
                this.textBox1.Text += "try1 \n";
                throw new Exception("tryの中で例外発生!");
            }
            catch
            {
                this.textBox1.Text += "catch1 \n";
                throw new Exception("catchの中で例外発生!");
            }
            finally
            {
                this.textBox1.Text += "finally1 \n";
            }
        }

Application クラスの DispatcherUnhandledException イベントを使うと、ハンドルされていない例外を一括して処理することができます。
ハンドルされていない例外が発生すると、Application クラスの DispatcherUnhandledException イベントが発生します。
ここでは、イベントハンドラで、メッセージボックスを出して、アプリケーションを継続するようにしています。

<Application x:Class="TryCatchTest.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml" 
             DispatcherUnhandledException="Application_DispatcherUnhandledException_1">
</Application>

using System.Windows;
using System.Windows.Threading;

namespace TryCatchTest
{
    public partial class App Application
    {
        private void Application_DispatcherUnhandledException_1(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            MessageBox.Show(e.Exception.Message);
            e.Handled = true;
        }
    }
}

0 件のコメント:

コメントを投稿