具有字符串赋值和获取值的表达式树

我已经构建了自己的SQL查询构建器,它拆分了一个Expression,但是,我在尝试获取与lambda表达式相同的函数中定义的字符串值时遇到了问题。

这是我在控制台应用程序中尝试做的事情:

private static void MyBuilderTest() { var sqlBuilder = new SqlBuilder(); // Doesn't work -- NEED GUIDANCE HERE var testValue = "Test"; // Defined in the same function as the lambda below sqlBuilder.Select(o => o.FooValue == testValue); // Works var someObject = new SomeObject { SomeValue = "classTest }; sqlBuilder.Select(o => o.FooValue == someObject.SomeValue); } 

在我的构建器中,它是ExpressionVisitor的子类,我重写了VisitMember。 我发现在基本控制台级别定义的字符串将返回:

 Node.Expression.NodeType == ExpressionType.Constant 

Node.Expression传回以下属性:

 CanReduce = false DebugView = ".Constant<ConsoleApplication1.Program+c__DisplayClass1>(ConsoleApplication1.Program+c__DisplayClass1)" NodeType = Constant Type = System.Type {System.RunetimeType} Value = {ConsoleApplication1.Program} 

Node.Expression.Value包含:

 testValue = "Test" (Type: string) 

我如何获得这个价值? 我尝试了几件事,比如:

 var memberType = node.Expression.Type.DeclaringType; 

这会传回ConsoleApplication1.Program类型。

但是,当我这样做时:

  memberType.GetProperty("testValue"); // Declaring Type from Expression 

它传回null。

如果我将lambda“strings”放在一个类中,上面的方法可以正常工作,但如果在控制台函数中定义了string,则它们不起作用。

任何人都可以告诉我如何获得字符串值,如果它在lambda的函数级别定义?

编辑:添加了VisitMember

 protected override Expression VisitMember(MemberExpression node) { if (node.NodeType == ExpressionType.Constant) { // Node.Expression is a ConstantExpression type. // node.Expression contains properties above // And Has Value of: {ConsoleApplication1.Program} // Expanding Value in Watch window shows: testValue = "Test" // How do I get this value, if the ConsoleApplication1.Program type doesn't // even know about it? Looks like maybe a dynamic property? } } 

EDITED

在控制台应用示例中添加了代码,以显示哪些有效,哪些无效。

示例中的lambda已“关闭” testValue变量,这意味着编译器已将其捕获为名为ConsoleApplication1.Program+<>c__DisplayClass1>的自动生成的类中的同名字段。 您可以使用常规reflection通过将二进制表达式的右侧强制转换为MemberExpression来获取该字段的当前值。

 var testValue = "hello"; var expr = (Expression>) (x => x == testValue); var rhs = (MemberExpression) ((BinaryExpression) expr.Body).Right; var obj = ((ConstantExpression) rhs.Expression).Value; var field = (FieldInfo) rhs.Member; var value = field.GetValue(obj); Debug.Assert(Equals(value, "hello")); testValue = "changed"; value = field.GetValue(obj); Debug.Assert(Equals(value, "changed")); 

或者,您可以将变量更改为常量。

 const string testValue = "hello"; var expr = (Expression>) (x => x == testValue); var value = ((ConstantExpression) ((BinaryExpression) expr.Body).Right).Value; Debug.Assert(Equals(value, "hello")); 

不要自己这样做,而是看看Matt Warren的PartialEvaluator 。 它用常量本身替换所有对常量的引用。