2016-07-27 170 views
-5

我想寫一個擴展方法來更自然地拋出新的異常(通常好奇關鍵字'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中,而不是擴展方法,因爲它在拋出時會停止方法的執行。

編輯: 應用程序不會編譯因爲該方法不會所有的代碼路徑都返回一個有效的結果(如異常會在擴展方法拋出,而不是原來的方法)

+1

的方法不編譯 - 「不是所有的代碼路徑返回一個值」。你的意思是「不起作用」? –

+0

你能澄清究竟發生了什麼嗎?它拋出什麼錯誤?據我所知,這應該工作(並拋出'失敗返回酒吧') – FrankerZ

+3

當你說這是行不通的,你的意思是? –

回答

1

我相信this是你在找什麼。 jist是,編譯器需要靜態驗證你是從每個代碼路徑返回的東西。因爲你使用這個擴展方法,它不能夠推斷的事實,而你得到的錯誤:

CS0161 'Foo()': not all code paths return a value

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有構造 要求),所以你必須添加反射

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; 
    } 

其是,IMHO,少可讀,因此不應該被用於

+0

使用上面的實現我仍然與最初的問題坐在'不是所有的代碼路徑返回一個值'的事情是我只是想知道爲什麼編譯器沒有拿起引發的異常在擴展方法。 FrankerZ引用的答案解釋了爲什麼會發生這種情況 –