2017-08-31 112 views
4

所以我一直在修補Linq.Expressions(如果有人可以建議一個更合適或更優雅的方式來做我所做的事情,請隨時參加),並試圖做一些事情已經碰壁了。Linq.Expression TryCatch - 將異常傳遞給Catch Block?

讓我們想象一下,我們有一個簡單的數學類:

public class SimpleMath { 
    public int AddNumbers(int number1, int number2) {   
     return number1 + number2; 
    } 
} 

我決定我想我們AddNumbers方法轉換成一個簡單的Func<object, object, object>委託。

要做到這一點,我做了以下內容:

// Two collections, one for Type Object paramaters and one for converting to Type int. 
List<ParameterExpression> parameters = new List<ParameterExpression>(); 
List<Expression> convertedParameters = new List<Expression>(); 

// Populate collections with Parameter and conversion 
ParameterExpression parameter1 = Expression.Parameter(typeof(object)); 
parameters.Add(parameter1); 
convertedParameters.Add(Expression.Convert(parameter1, typeof(int))); 

ParameterExpression parameter2 = Expression.Parameter(typeof(object)); 
parameters.Add(parameter2); 
convertedParameters.Add(Expression.Convert(parameter2, typeof(int))); 

// Create instance of SimpleMath 
SimpleMath simpleMath = new SimpleMath(); 

// Get the MethodInfo for the AddNumbers method 
MethodInfo addNumebrsMethodInfo = simpleMath.GetType().GetMethods().Where(x => x.Name == "AddNumbers").ToArray()[0]; 
// Create MethodCallExpression using the SimpleMath object, the MethodInfo of the method we want and the converted parameters 
MethodCallExpression returnMethodWithParameters = Expression.Call(Expression.Constant(simpleMath), addNumebrsMethodInfo, convertedParameters); 

// Convert the MethodCallExpression to return an Object rather than int 
UnaryExpression returnMethodWithParametersAsObject = Expression.Convert(returnMethodWithParameters, typeof(object)); 

// Create the Func<object, object, object> with our converted Expression and Parameters of Type Object 
Func<object, object, object> func = Expression.Lambda<Func<object, object, object>>(returnMethodWithParametersAsObject, parameters).Compile(); 
    object result = func(20, 40); // result = 60 

所以,如果你運行該代碼func應該返回簡單的計算。然而,它接受類型對象,這顯然離開它打開在運行時的問題,例如參數:

object result1 = func(20, "f"); // Throws InvalidCastException 

所以我想換的方法,在Try...Catch(顯然這個確切的問題將在編譯有所回升如果我們正在處理直接調用AddNumbers並傳遞一個字符串作爲參數)。

以抓住這個例外,我可以做到以下幾點:

TryExpression tryCatchMethod = TryExpression.TryCatch(returnMethodWithParametersAsObject, Expression.Catch(typeof(InvalidCastException), Expression.Constant(55, typeof(object)))); 
Func<object, object, object> func = Expression.Lambda<Func<object, object, object>>(tryCatchMethod, parameters).Compile(); 
object result = func(20, "f"); // result = 55 

TryExpression.TryCatch需要一個表達的身體,然後CatchBlock處理程序的集合。 returnMethodWithParametersAsObject是我們希望包裹的表達,Expression.Catch定義了我們想捕獲異常是InvalidCastException類型和它表達的身體是一個常數,55

所以異常的處理,但除非我想這是沒有多大用處在拋出異常時總是返回一個靜態值。於是久違的SimpleMath I類添加一個新方法HandleException

public class SimpleMath { 
    public int AddNumbers(int number1, int number2) { 
     return number1 + number2; 
    } 

    public int HandleException() { 
     return 100; 
    } 
} 

而且同樣的過程上面我轉換的新方法的表達式:

MethodInfo handleExceptionMethodInfo = simpleMath.GetType().GetMethods().Where(x => x.Name == "HandleException").ToArray()[0]; 
MethodCallExpression returnMethodWithParameters2 = Expression.Call(Expression.Constant(simpleMath), handleExceptionMethodInfo); 
UnaryExpression returnMethodWithParametersAsObject2 = Expression.Convert(returnMethodWithParameters2, typeof(object)); 

然後創建TryCatch塊時使用它:

TryExpression tryCatchMethod2 = TryExpression.TryCatch(returnMethodWithParametersAsObject, Expression.Catch(typeof(InvalidCastException), returnMethodWithParametersAsObject2)); 
Func<object, object, object> func = Expression.Lambda<Func<object, object, object>>(tryCatchMethod2, parameters).Compile(); 
object result = func(20, "f"); // result = 100 

所以當InvalidCastException拋出的SimpleMath.HandleException方法這段時間將被執行。到目前爲止,如果出現異常,我現在可以執行一些代碼。

我現在的問題是,在一個正常的行內嘗試...趕上塊你實際上有你的處置異常對象。例如。

try { 
    // Do stuff that causes an exception 
} catch (InvalidCastException ex) { 
    // Do stuff with InvalidCastException ex 
} 

時拋出一個異常,我可以執行代碼,但我似乎無法弄清楚如何真正得到我的手異常對象上,就像您在普通try ... catch塊。

任何幫助,將不勝感激!

p.s.我知道你不會以上述方式組織任何事情,但我認爲有必要舉例說明我想要做什麼的機制。

+0

問題比較對我的知識,而是一個建議,可以幫助有關傳遞異常太複雜:抓{拋出;}。這會將你的異常傳遞給調用方法(你必須處理它或程序將停止!)。如果你想把你的手放在一個已經存在的函數的例外,把它作爲一個動作/ func在你自己的TryCatch方法中,如果發生了什麼錯誤,返回一個異常,如果一切正常,你認爲是好的(空?) – Kinxil

回答

1

您需要將您的捕獲異常傳遞給CatchBlock表達式作爲參數。 對於這一點,你應該做的:的HandleException

  • 更改簽名。這將需要一個異常作爲參數:

    public int HandleException(InvalidCastException exp) 
    { 
        // Put here some real logic. I tested it using line below 
        Console.WriteLine(exp.Message); 
        return 100; 
    } 
    
  • 使用CatchBlock.Variable通過您處理的異常到catch塊。你可以設置它使用構造函數。閱讀評論請在下面的代碼:

    // Create parameter that will be passed to catch block 
        var excepParam = Expression.Parameter(typeof(InvalidCastException)); 
    
        MethodInfo handleExceptionMethodInfo = simpleMath.GetType().GetMethods().Where(x => x.Name == "HandleException").ToArray()[0]; 
        MethodCallExpression returnMethodWithParameters2 = Expression.Call(Expression.Constant(simpleMath), handleExceptionMethodInfo, excepParam); 
        UnaryExpression returnMethodWithParametersAsObject2 = Expression.Convert(returnMethodWithParameters2, typeof(object)); 
    
        // Put created parameter before to CatchBlock.Variable using Expression.Catch 
        // that takes the first argument as ParameterExpression 
        TryExpression tryCatchMethod2 = TryExpression.TryCatch(returnMethodWithParametersAsObject, Expression.Catch(excepParam, returnMethodWithParametersAsObject2)); 
        var exppp = Expression.Lambda<Func<object, object, object>>(tryCatchMethod2, parameters); 
        Func<object, object, object> func2 = Expression.Lambda<Func<object, object, object>>(tryCatchMethod2, parameters).Compile(); 
        object result2 = func2(20, "f"); // result = 100 
    
+0

傑出!這正是我所期待的,非常感謝。 – David