I am trying to create a method for (at runtime) creating wrappers for delegates of all types. This will create a flexible way to enter additional logs (in this case). In this first step, I tried to create a try-catch wrapper around a given input -argument.
try { Console.WriteLine(....);
I use a generic call to the CreateWrapper2 method (see below)
private static readonly MethodInfo ConsoleWriteLine = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object[]) }); private static MethodCallExpression WriteLinExpression(string format, params object[] args) { Expression[] expressionArguments = new Expression[2]; expressionArguments[0] = Expression.Constant(format, typeof(string)); expressionArguments[1] = Expression.Constant(args, typeof(object[])); return Expression.Call(ConsoleWriteLine, expressionArguments); } public T CreateWrapper2<T>(T input) { Type type = typeof(T); if (!typeof(Delegate).IsAssignableFrom(type)) { return input; } PropertyInfo methodProperty = type.GetProperty("Method"); MethodInfo inputMethod = methodProperty != null ? (MethodInfo)methodProperty.GetValue(input) : null; if (inputMethod == null) { return input; } string methodName = inputMethod.Name; ParameterInfo[] parameters = inputMethod.GetParameters(); ParameterExpression[] parameterExpressions = new ParameterExpression[parameters.Length];
For void methods (e.g. Action<> ) this code does what I need. But when there is a return value, I get a "variable" exception of type "System.Boolean" that refers to the scope of "but not defined"
Many other posts talk about Expression.Parameter called more than once for a parameter; it seems to me that something is wrong here, but I cannot find it. Everything goes well to the .Compile line, there it crashes.
For Func<int, bool> target = i => i % 2 ==0; Below is the DebugView for the generated expression.
.Lambda #Lambda1<System.Func`2[System.Int32,System.Boolean]>(System.Int32 $i) { .Block() { $var1; .Try { .Block() { .Call System.Console.WriteLine( "Starting '{0}'.", .Constant<System.Object[]>(System.Object[])); $var1 = .Call LDAP.LdapProgram.<Main>b__0($i); .Call System.Console.WriteLine( "Completed '{0}'.", .Constant<System.Object[]>(System.Object[])); .Return #Label1 { $var1 } } } .Catch (System.Exception) { .Block() { .Call System.Console.WriteLine( "Failed '{0}'.", .Constant<System.Object[]>(System.Object[])); .Rethrow } }; .Label .Default(System.Boolean) .LabelTarget #Label1: } }
What am I missing? (during debug hours, I tried:
- move
Expression.Variable from inside the body try to thevelvel. - gave the catch block the same Body.Type as the try-block, using typed-
Expression.Return .
)