【问题标题】:Is a generic exception supported inside a catch?catch 中是否支持通用异常?
【发布时间】:2013-06-05 10:39:06
【问题描述】:

上面提到的关于 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 类型的预期异常被抛出时,它总是被第二个catch 捕获,而不是第一个catch。为什么是这样?

当然,我可以使用一次捕获并测试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!!!");
            }
        }
    }
}

【问题讨论】:

  • 你使用什么单元测试框架?大多数已经有Assert.Throws...
  • 您的代码对我有用...请展示一个简短但完整的程序来说明问题。
  • @Jon Skeet:忘掉单元测试故事吧……这是一个关于 try-catch 的问题。
  • @ChrisSpicer:我的目标是 .NET 4.5,但我很乐意尝试其他版本……一旦我们有了一个简短但完整的程序来演示 OP 的问题。目前我们只有 sn-ps,我更想知道我有完全相同的完整应用程序。

标签: c# visual-studio-2008 generics try-catch


【解决方案1】:

您不是第一个遇到此问题的人。 This question 非常相似。如果您仔细研究答案和链接,则可以归结为 CLR 中的一个错误。

编辑: 作为后续,我从 VS2010 运行 Martin 的示例并得到以下结果:

  • 以 .NET 4 为目标,通过
  • 针对 .NET 3.5,失败
  • 在 RELEASE 模式下定位 .NET 3.5,PASS

遗憾的是,Microsoft Bug Report 的所有 SO 链接现在都已失效,我无法找到任何其他链接。

【讨论】:

  • 上一个问题早在 2009 年就已经回答了,现在还适用吗?
  • 好问题。我只是将 Martin 的代码放在 VS 中(稍作调整)。如果我以 .NET 4 为目标,则代码按预期工作。如果我以 3.5 为目标,我会看到 Martin 描述的奇怪行为。
  • 不适用。这两个问题相似,但另一个问题有一个额外的异常变量tex,(正确)答案是删除该变量。就我而言,我没有使用变量,因此该答案不适用于这种情况。
  • @ChrisSpicer: VS 2010,Win7 x64,Windows 更新已打开(因此,我有所有的修补程序和 SP,如果它们已发布)。我尝试了 4、3.5 和 2.0 目标(当然,2.0 还声明了 Action)。它按预期工作(属于catch (TException))。我做错了什么?
【解决方案2】:

(这不是一个具体的答案;但我也无法将其作为评论发布。)

我无法重现这一点(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

所以(恕我直言)你应该去别处看看。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 2021-02-09
    • 1970-01-01
    • 2020-03-26
    • 2019-10-07
    • 1970-01-01
    相关资源
    最近更新 更多