読者です 読者をやめる 読者になる 読者になる

xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

例外フィルター

C#

例外処理はtry句でスローされる例外の型に応じて処理を書き分けます。また、ひとつの例外の型でエラー条件が分かれる場合はcatch句の中にif文を書いて分岐します。例えば以下のような感じです。

try
{
    //--- SQL Serverへの何らかのアクセス
}
catch (SqlException ex)  //--- SqlExceptionの派生クラスに関する例外処理
{
    if (ex.Number == 1205)
    {
        //--- デッドロック発生時
    }
    else
    {
        //--- デッドロック以外のSqlExceptionに関する処理
    }
}
catch (Exception ex)
{
    //--- その他のすべての例外
}

C# vNextではこのエラーの条件分岐 (= if文) に当たる部分をcatch句の一部として書けるようになりました。つまり、catch句で引っ掛ける例外のフィルター機能です。書き方は簡単で、catch句の後ろにwhen句を入れるだけです。

try
{
    //--- SQL Serverへのアクセス
}
catch (SqlException ex) when (ex.Number == 1205)
{
    //--- デッドロック
}
catch (SqlException ex)
{
    //--- デッドロック以外のSqlExceptionに関する処理
}
catch (Exception ex)
{
    //--- その他のすべての例外
}

ネストを一段減らすことができるだけでなく、特定の条件に合わない例外処理を共通化できるようにもなります。

逆コンパイル

今回のサンプルはすべて.NET Framework 4.5ベースで試しています。「.NET Frameworkのバージョンが変わらない = IL機能は既存のまま」なので、例外フィルターはILレベルでは昔からサポートされていたことになります。ということで2014/6/29にリリースされた最新のILSpy v2.2を使ってC#に逆コンパイルし、既存のコードとしてどのように展開されるかを試してみました。

using System;
using System.Data.SqlClient;

namespace CSharpVNext
{
    class Program
    {
        static void Main()
        {
            try
            {
                return;
            }
            catch (SqlException ex_29)
            {
                return;
            }
            catch (Exception ex_2E)
            {
                return;
            }
            object arg_05_0;
            SqlException expr_0A = arg_05_0 as SqlException;
            int arg_22_0;
            if (expr_0A == null)
            {
                arg_22_0 = 0;
            }
            else
            {
                SqlException ex = expr_0A;
                arg_22_0 = (((ex.Number == 1205) > false) ? 1 : 0);
            }
            endfilter(arg_22_0);
        }
    }
}

...どう考えてもコレじゃない感。どうやら例外フィルターは既存のコードとして表現できるものではなく、例外フィルターのコードとしてちゃんと展開されるようにならなければならない気がします。ILSpyの今後の対応に期待しましょう。