我正在尝试为(在运行时)为所有类型的委托创建包装器创建一个方法.这样可以创建一种灵活的注入额外日志记录的方法(在本例中).在第一步中,我尝试围绕给定的input
-argument 创建try-catch包装.
try { Console.WriteLine(....); // Here the original call Console.WriteLine(....); } catch(Exception ex) { Console.WriteLine(.....); }
我正在使用泛型方法调用CreateWrapper2
(见下文)
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 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]; // TODO: Validate/test parameters, by-ref /out with attributes etc. for (int idx = 0; idx < parameters.Length; idx++) { ParameterInfo parameter = parameters[idx]; parameterExpressions[idx] = Expression.Parameter(parameter.ParameterType, parameter.Name); } bool handleReturnValue = inputMethod.ReturnType != typeof(void); ParameterExpression variableExpression = handleReturnValue ? Expression.Variable(inputMethod.ReturnType) : null; MethodCallExpression start = WriteLinExpression("Starting '{0}'.", methodName); MethodCallExpression completed = WriteLinExpression("Completed '{0}'.", methodName); MethodCallExpression failed = WriteLinExpression("Failed '{0}'.", methodName); Expression innerCall = Expression.Call(inputMethod, parameterExpressions); LabelTarget returnTarget = Expression.Label(inputMethod.ReturnType); LabelExpression returnLabel = Expression.Label(returnTarget, Expression.Default(returnTarget.Type)); ; GotoExpression returnExpression = null; if (inputMethod.ReturnType != typeof(void)) { // Handle return value. innerCall = Expression.Assign(variableExpression, innerCall); returnExpression = Expression.Return(returnTarget, variableExpression, returnTarget.Type); } else { returnExpression = Expression.Return(returnTarget); } List tryBodyElements = new List (); tryBodyElements.Add(start); tryBodyElements.Add(innerCall); tryBodyElements.Add(completed); if (returnExpression != null) { tryBodyElements.Add(returnExpression); } BlockExpression tryBody = Expression.Block(tryBodyElements); BlockExpression catchBody = Expression.Block(tryBody.Type, new Expression[] { failed, Expression.Rethrow(tryBody.Type) }); CatchBlock catchBlock = Expression.Catch(typeof(Exception), catchBody); TryExpression tryBlock = Expression.TryCatch(tryBody, catchBlock); List methodBodyElements = new List (); if(variableExpression != null) methodBodyElements.Add(variableExpression); methodBodyElements.Add(tryBlock); methodBodyElements.Add(returnLabel); Expression wrapperLambda = Expression .Lambda (Expression.Block(methodBodyElements), parameterExpressions); Console.WriteLine("lambda:"); Console.WriteLine(wrapperLambda.GetDebugView()); return wrapperLambda.Compile(); }
对于void-methods(比如Action<>
),这段代码可以满足我的需求.但是当有一个返回值时,我得到了从范围''引用的'System.Boolean'类型的异常" 变量",但它没有被定义 "
许多其他帖子谈论Expression.Parameter
不止一次为参数调用; 对我来说,这里看起来像是其他错误,但我找不到它.一切顺利,直到.Compile
它崩溃.
对于Func
下面是生成的表达式的DebugView.
.Lambda #Lambda1(System.Int32 $i) {
.Block() {
$var1;
.Try {
.Block() {
.Call System.Console.WriteLine(
"Starting '{0}'.",
.Constant(System.Object[]));
$var1 = .Call LDAP.LdapProgram.b__0($i);
.Call System.Console.WriteLine(
"Completed '{0}'.",
.Constant(System.Object[]));
.Return #Label1 { $var1 }
}
} .Catch (System.Exception) {
.Block() {
.Call System.Console.WriteLine(
"Failed '{0}'.",
.Constant(System.Object[]));
.Rethrow
}
};
.Label
.Default(System.Boolean)
.LabelTarget #Label1:
}
}
我错过了什么?(在调试期间我试过:
Expression.Variable
从try-body内部移动到顶层.
通过typed-给catch块提供了与try-block相同的Body.Type Expression.Return
.
)