当前位置:  开发笔记 > 编程语言 > 正文

"范围''引用的'System.Boolean'类型的"变量",但未在Expression中定义

如何解决《"范围''引用的'System.Boolean'类型的"变量",但未在Expression中定义》经验,为你挑选了0个好方法。

我正在尝试为(在运行时)为所有类型的委托创建包装器创建一个方法.这样可以创建一种灵活的注入额外日志记录的方法(在本例中).在第一步中,我尝试围绕给定的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 target = i => i % 2 ==0;下面是生成的表达式的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.

)

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有