12

SOに関する別の質問+回答を参照する上記のブロックには、ここに適用される正解は含まれていません!

単体テストに使用されるメソッドがあります。このメソッドの目的は、(デリゲートによって参照される) コードの一部が特定の例外を確実にスローするようにすることです。その例外がスローされた場合、単体テストは成功します。例外がスローされない場合、または別のタイプの例外がスローされる場合、単体テストは失敗します。

/// <summary>
/// Checks to make sure that the action throws a exception of type TException.
/// </summary>
/// <typeparam name="TException">The type of exception expected.</typeparam>
/// <param name="action">The code to execute which is expected to generate the exception.</param>
public static void Throws<TException>(Action action) 
    where TException : Exception
{
    try
    {
        action();
    }
    catch (TException)
    {
        return;
    }
    catch (Exception ex)
    {
        Assert.Fail("Wrong exception was thrown. Exception of type " + ex.GetType() + " was thrown, exception of type " + typeof(TException) + " was expected.");
    }
    Assert.Fail("No exception was thrown. Exception of type " + typeof(TException) + " was expected.");
}

次の呼び出しは成功するはずですが、失敗します。

int result = 0;
Throws<DivideByZeroException>(() => result = result / result);

タイプの予期される例外TExceptionがスローされると、最初のキャッチではなく、常に 2 番目のキャッチによってキャッチされます。どうしてこれなの?

もちろん、1 つのキャッチで回避策を使用して、exタイプが であるかどうかをテストできますTException。このコードがコンパイルされる理由を知りたい/理解したいだけですが、単純な(決して?) 動作します。

編集

要求に応じて「動作する」デモ:

using System;

namespace GenericExceptionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int n = 0;
            Catch<DivideByZeroException>(() => n = n / n);
        }

        static public void Catch<TException>(Action action)
            where TException: Exception
        {
            try
            {
                action();
                Console.WriteLine("No exception thrown. !!!Fail!!!");
            }
            catch (TException)
            {
                Console.WriteLine("Expected exception thrown. PASS!");
            }
            catch(Exception ex)
            {
                Console.WriteLine("An unexpected exception of type " + ex.GetType() + " thrown. !!!FAIL!!!");
            }
        }
    }
}
4

2 に答える 2

2

この問題に遭遇したのはあなたが初めてではありません。この質問 は非常に似ています。回答とリンクを掘り下げると、CLR のバグに行き着きます。

編集: フォローアップとして、VS2010 から Martin の例を実行したところ、次の結果が得られました。

  • .NET 4、PASS をターゲットにする
  • .NET 3.5 をターゲットにする、FAIL
  • RELEASE モードで .NET 3.5 をターゲットにすると、PASS

残念ながら、Microsoft Bug Report への SO リンクはすべて無効になっており、他に見つけることができませんでした。

于 2013-06-05T10:58:53.047 に答える
0

(これは具体的な答えではありませんが、コメントとして投稿することもできませんでした。)

これを再現できません (VS 2012、.NET 4.5、C# 5.0、すべての SP がインストールされています)。

この例外クラスを定義しました:

class MyException : Exception
{
    public MyException() { }
    public MyException(string message) : base(message) { }
}

そして方法:

static void Throws<T>(Action action) where T : Exception
{
    try
    {
        action();
    }
    catch (T) { Console.WriteLine("got {0}", typeof(T)); }
    catch (Exception) { Console.WriteLine("got Exception"); }
}

そして私はそれをこのようにテストしました:

Throws<MyException>(() => { throw new MyException(); });

int result = 0;
Throws<DivideByZeroException>(() => result = result / result);

出力は次のとおりです。

  • Draft.MyException を取得しました
  • System.DivideByZeroException を取得しました

だから(私見)あなたはどこか他の場所を見るべきです。

于 2013-06-05T12:17:46.407 に答える