gpt4 book ai didi

c# - "variable ' ' of type ' System.Boolean ' referenced from scope ' ', but it is not defined"在表达式中

转载 作者:太空狗 更新时间:2023-10-29 23:50:10 26 4
gpt4 key购买 nike

我正在尝试创建一种方法(在运行时)为所有类型的委托(delegate)创建包装器。这是为了创建一种灵活的方式来注入(inject)额外的日志记录(在本例中)。在这第一步中,我尝试围绕给定的 input 创建一个 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>(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();
}

对于 void 方法(如 Action<>),这段代码可以满足我的需要。但是当有返回值时,我得到异常“从范围''引用的'System.Boolean'类型的变量'',但它未定义

许多其他帖子都在谈论Expression.Parameter多次调用一个参数;对我来说,这里似乎有其他问题,但我找不到。一切顺利,直到 .Compile线,在那里它崩溃了。

对于 Func<int, bool> target = i => i % 2 ==0;下面是生成的表达式的 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:
}
}

我错过了什么?(在调试期间我试过:

  • 移动Expression.Variable从 try-body 内部到顶层。
  • 通过 typed- Expression.Return 为 catch block 提供与 try block 相同的 Body.Type .

)

最佳答案

看起来您没有为 block 语句指定变量。

在错误中你正在创建一个参数并且没有给它一个名字,如果你这样做你会看到:

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

因此,为了将来引用,如果您在制作表达式树时给您的 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();

关于c# - "variable ' ' of type ' System.Boolean ' referenced from scope ' ', but it is not defined"在表达式中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34356639/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com