Linq.Expression TryCatch - Throw exception from Catch Block?

So, I did Linq.Expressions (and if someone can suggest a more correct or more elegant way of doing what I do, feel free to call) and hit the wall trying to do something,

Suppose we have a simple math class:

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

I decided that I want to convert our method AddNumbersto a simple delegate Func<object, object, object>.

To do this, I do the following:

// 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

So, if you run this code func, you need to return simple calculations. However, it accepts Type Object parameters, which obviously leave it open to run-time problems, for example:

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, 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... Catch block . .

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

, , , , Try... Catch.

!

p.s. , , , , , .

+4
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
    
+1

Source: https://habr.com/ru/post/1684830/


All Articles