2017-08-31 62 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