本地变量和表达式树

20 浏览
0 Comments

本地变量和表达式树

我正在学习C#中的表达式树。

我现在遇到了一些困难:

string filterString = "ruby";
Expression> expression = x => x == filterString;

我该如何通过代码构建这个表达式?没有示例来捕获局部变量。这个很简单:

Expression> expression = x => x == "ruby";

可以这样做:

ParameterExpression stringParam = Expression.Parameter(typeof(string), "x");
Expression constant = Expression.Constant("ruby");
BinaryExpression equals = Expression.Equal(stringParam, constant);
Expression> lambda1 =
    Expression.Lambda>(
        equals,
        new ParameterExpression[] { stringParam });

调试器打印出(x => x == filterString)的内容如下:

{x => (x ==

value(Predicate.Program+<>c__DisplayClass3).filterString)}

感谢对这个主题的解释。

0
0 Comments

这段代码中的问题是将表达式包装在一个闭包块中,将局部变量视为常量。原因是在表达式树中,局部变量被视为常量,而不是作为变量进行处理。这可能导致一些意想不到的结果,特别是在使用局部变量进行比较时。

解决方法是创建一个新的参数来表示局部变量,而不是将其视为常量。这样可以确保在表达式树中正确地处理局部变量。

以下是修复问题的代码:

string filterString = "ruby";
var filterStringParam = Expression.Parameter(typeof(string), "filterString");
var stringParam = Expression.Parameter(typeof(string), "x");
var block = Expression.Block(
    // Add a local variable.
    new[] { filterStringParam },
    // Assign the parameter to the local variable: filterStringParam = stringParam
    Expression.Assign(filterStringParam, stringParam),
    // Compare the parameter to the local variable
    Expression.Equal(stringParam, filterStringParam));
var x = Expression.Lambda>(block, stringParam).Compile();

通过使用新的参数来表示局部变量,并将其与其他参数进行比较,可以确保正确处理局部变量。这样,无论何时使用表达式树进行计算,都可以得到预期的结果。

0
0 Comments

问题的出现原因是在表达式树中捕获局部变量时,实际上是通过将局部变量"提升"为一个编译器生成的类的实例变量来实现的。C#编译器在适当的时候创建一个额外类的新实例,并将对局部变量的任何访问更改为对相关实例中实例变量的访问。

因此,表达式树需要是实例内的字段访问 - 并且实例本身是通过ConstantExpression提供的。

解决方法通常是通过在lambda表达式中创建类似的东西,然后在反编译器中查看生成的代码,将优化级别调低,以便反编译器不会将其转换回lambda表达式。

另一个解决方法是使用Expression.Property方法,例如:`var hoistedConstant = Expression.Property(Expression.Constant(new {Value = filterString}), "Value");`。

某些情况下了使用Expression.Constant方法的解决方法,例如:`Expression.Constant(filterString)`,但是这种方法不会反映变量的更改。

还某些情况下了使用lambda表达式的解决方法,例如:`var variableAccessor = ((Expression>)(() => filterString)).Body;`。

最后,某些情况下了查看生成的MSIL代码的提示对于解决问题很有帮助。

总之,解决这个问题的方法包括使用Expression.Property方法、Expression.Constant方法和lambda表达式,并查看生成的代码来了解表达式树的创建。

0
0 Comments

(Local variable and expression trees)这个问题的出现是因为在构建用于Linq-to-entities (L2E)的表达式时,无法使用Expression.Block,因为它无法解析为SQL。

解决方法是创建一个辅助类来包含过滤器的值。具体步骤如下:

1. 创建一个辅助类ExpressionScopedVariables来包含过滤器的值。

2. 构建表达式树:

- 创建一个ExpressionScopedVariables对象scope,并将filterString的值赋给它。

- 创建一个表示scope的常量表达式filterStringExp。

- 使用反射获取ExpressionScopedVariables类中的Value属性,并创建一个成员访问表达式access。

3. 将原始代码中的常量替换为成员访问表达式access。

4. 构建最终的表达式树lambda1。

以上方法对于L2E非常有用,可以根据实际需求进行适当的调整。

这个方法帮助了我很多,非常感谢!虽然我的需求有些不同,但是创建一个"scope"类并从中创建一个表达式的概念指导了我走向正确的方向。

非常感谢!这真的很有帮助!

0