简体   繁体   English

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

[英]“variable '' of type 'System.Boolean' referenced from scope '', but it is not defined” in Expression

I am trying to create a method for (at runtime) creating wrappers for delegates of all types. 我正在尝试为(在运行时)为所有类型的委托创建包装器创建一个方法。 This to create a flexible way of injecting additional logging (in this case). 这样可以创建一种注入额外日志记录的灵活方式(在本例中)。 In this first step i tried to create a try-catch wrap around the given input -argument. 在第一步中,我尝试围绕给定的input -argument创建try-catch包装。

try
{
  Console.WriteLine(....);
  // Here the original call
  Console.WriteLine(....);
}
catch(Exception ex)
{
  Console.WriteLine(.....);
}

I am using a generic method call CreateWrapper2 (see below) 我正在使用泛型方法调用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>(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<Expression> tryBodyElements = new List<Expression>();
    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<Expression> methodBodyElements = new List<Expression>();

    if(variableExpression != null) methodBodyElements.Add(variableExpression);

    methodBodyElements.Add(tryBlock);
    methodBodyElements.Add(returnLabel);

    Expression<T> wrapperLambda = Expression<T>.Lambda<T>(Expression.Block(methodBodyElements), parameterExpressions);

    Console.WriteLine("lambda:");
    Console.WriteLine(wrapperLambda.GetDebugView());

    return wrapperLambda.Compile();
}

For void-methods (like Action<> ) this code does what i need. 对于void-methods(如Action<> ),这段代码可以满足我的需要。 But when there is a return value i get the exception " variable '' of type 'System.Boolean' referenced from scope '', but it is not defined " 但是当有一个返回值时,我得到了从范围''引用的'System.Boolean'类型的异常“ 变量”,但它没有被定义

Many other posts talk about Expression.Parameter called more than once for a parameter; 许多其他帖子谈论Expression.Parameter多次为参数调用; to me it look like here is something else is wrong here but i can't find it. 对我来说,这里看起来像是其他错误,但我找不到它。 All goes well untill the .Compile line, there it crashes. 一切顺利,直到.Compile行,它崩溃了。

For a Func<int, bool> target = i => i % 2 ==0; 对于Func<int, bool> target = i => i % 2 ==0; below is the DebugView for the generated expression. 下面是生成的表达式的DebugView。

.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 the debugging hours i tried: (在调试期间我试过:

  • moving the Expression.Variable from inside the try-body to the toplevel. Expression.Variable从try-body内部移动到toplevel。
  • gave the catch-block the same Body.Type as the try-block via the typed- Expression.Return . 通过typed- Expression.Return给catch块提供了与try-block相同的Body.Type。

)

It looks like you aren't specifying your varaibles for the block statement. 看起来你没有为block语句指定你的变量。

In the error you're creating a parameter on the fly and not giving it a name, if you did you would have seen : 在错误中,你正在动态创建一个参数,而不给它一个名字,如果你这样做,你会看到:

"variable 'varName' of type 'System.Boolean' referenced from scope 'varName', but it is not defined"

So for future reference can make your life a lot easier if you give your vars names when making expression trees the following should work 因此,如果您在制作表达式树时提供您的vars名称,以后应该可以使您的生活更轻松

        // Define the variable at the top of the block 
        // when we are returning something
        if (variableExpression != null)
        {
            block = Expression.Block(new[] { variableExpression }, methodBodyElements);
        }
        else
        {
            block = Expression.Block(methodBodyElements);
        }

        Expression<T> wrapperLambda = Expression<T>.Lambda<T>(block, parameterExpressions);

        return wrapperLambda.Compile();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 范围“”引用了类型为“ System.String”的Expression.Lambda变量,但未定义 - Expression.Lambda variable '' of type 'System.String' referenced from scope '', but it is not defined 表达式树中的错误:System.InvalidOperationException:从范围&#39;&#39;引用的类型&#39;A&#39;的变量&#39;消息&#39;,但未定义 - Error in expression tree: System.InvalidOperationException: variable 'message' of type 'A' referenced from scope '', but it is not defined Linq表达式-从范围“”引用的类型为“ System.Data.DataRow”的“变量”,但未定义 - Linq expression - “variable” of type 'System.Data.DataRow' referenced from scope “” but it is not defined 类型“System.Func`2[T,System.Boolean]”的表达式不能用于返回类型“System.Boolean” - Expression of type 'System.Func`2[T,System.Boolean]' cannot be used for return type 'System.Boolean' Expression.Or - 从范围&#39;&#39;引用的&#39;约会&#39;类型的变量&#39;a&#39;,但它没有定义 - Expression.Or - variable 'a' of type 'Appointment' referenced from scope '', but it is not defined Expression.Lambda:变量&#39;&#39;&#39;类型&#39;&#39;引用范围&#39;&#39;,但它没有定义 - Expression.Lambda: Variable 'x' of type '' referenced from scope '', but it is not defined System.InvalidOperationException:从范围``引用的类型&#39;&#39;的变量&#39;&#39;,但未定义 - System.InvalidOperationException: Variable '' of type '' referenced from scope '', but it is not defined 范围“”引用了类型为“ System.Data.DataRow”的变量“,但未定义 - Variable '' of type 'System.Data.DataRow' referenced from scope '', but it is not defined 变量&#39;&#39;类型&#39;&#39;从范围&#39;&#39;引用,但它没有定义 - variable '' of type '' referenced from scope '', but it is not defined GraphQL:类型变量引用自 scope,但未定义 - GraphQL: Variable of type referenced from scope, but it is not defined
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM