抛出新Exception的扩展方法

时间:2016-07-27 08:07:15

标签: c# exception-handling

我想编写一个扩展方法来更自然地抛出新的异常(通常很好奇关键字' throw'实际上是如何工作的)。我想知道为什么以下代码不起作用:

    public static bool Foo() {
        bool bar = false;
        try {
            var zero = 0;
            // force exception
            var result = 1 / zero;
            return bar;
        } catch (Exception ex) {
            ex.ThrowNew("Failed to return Bar");
            // instead of throw new Exception("Failed to return Bar", ex);
        }
    }

ex.ThrowNew方法是以下扩展方法:

    public static void ThrowNew(this Exception ex, string message) {
        throw new Exception(message, ex);
    }

显然,当异常抛出在catch中时,Foo()方法正常工作,而不是扩展方法,因为它在抛出时停止执行该方法。

修改 应用程序不会编译,因为该方法并非所有代码路径都返回有效结果(因为异常将在Extension方法中抛出,而不是原始方法)

2 个答案:

答案 0 :(得分:1)

我相信this是您正在寻找的。问题是,编译器需要静态验证您是否从每个代码路径返回一些内容。由于您使用的是此扩展程序,因此无法推断出这一事实,并且您收到了错误消息:

  

CS0161' Foo()':并非所有代码路径都返回值

答案 1 :(得分:1)

投掷Exception课程是不良做法以及在没有通过Exception重新投掷的情况下抓住throw;(请注意语法):

// Whatever happened (e.g. CPU starts emittinig green smoke) 
} catch (Exception ex) {
   // throw Exception instance which means nothing more than "Something went wrong"
   ex.ThrowNew("Failed to return Bar");
} 

首先,让我们修改初始代码:

try {
  ...
}
// We do know the cause, that's why we have a right to catch and re-throw 
catch (DivideByZeroException e) {
  // Be specific, do not throw Exception! Since MyBarException can be caought in "catch"
  throw new MyBarException("Failed to return Bar because...", e);
}

我怀疑你是否想要任何扩展方法,但是,如果你坚持要把它放在像

这样的东西上
// Doesn't compile; to show the idea only
public static void ThrowNew<T>(this Exception ex, string message) 
  where T: Exception {

  if (null == ex)
    return; // or throw ArgumentNullException("ex");

  throw new T(message, ex); // <- this line fails to compile
}

上面的代码存在new T的问题(.Net无法确定任意T是否具有构造函数 必填),所以你必须为

添加 Reflection
public static void ThrowNew<T>(this Exception ex, string message) 
  where T: Exception {

  if (null == ex)
    return; // or throw ArgumentNullException("ex");

  throw (Exception) (typeof(T)
    .GetConstructor(new Type[] { typeof(String), typeof(Exception)})
    .Invoke(message, ex));
}

所以你可以把

    catch (DivideByZeroException e) {
      e.ThrowNew<MyBarException>("Failed to return Bar because...");

      // Ugly little thing: 
      // "if (null == ex)" in the extension method doesn't throw any exception
      return false;
    }

,恕我直言,不太可读,因此不应使用