Expression tree with string assignment and getting value

I built my own SQL Query constructor that breaks the expression, however, I am having trouble trying to get the value of a string defined in the same function as the lambda expression.

Here is what I am trying to do in a console application:

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<FooObject>(o => o.FooValue == testValue); // Works var someObject = new SomeObject { SomeValue = "classTest }; sqlBuilder.Select<FooObject>(o => o.FooValue == someObject.SomeValue); } 

In my builder, these are subclasses from ExpressionVisitor, and I override VisitMember. I found that a line defined at the base level of the console will return as:

 Node.Expression.NodeType == ExpressionType.Constant 

Node.Expression returns the properties:

 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 contains:

 testValue = "Test" (Type: string) 

How do I get this value? I tried several things, for example:

 var memberType = node.Expression.Type.DeclaringType; 

This returns the type ConsoleApplication1.Program.

However, when I do this:

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

It returns null.

The above methods work fine if I put lambda strings in a class, but don't work if they are defined in the console function.

Can someone tell me how to get a string value if it is defined at the level of the lambda function?

EDITED: Added by 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

Added code to the console application example to show what works and what doesn't.

+4
source share
2 answers

In your example, lambda has a "private" variable testValue , that is, the compiler fixed it as a field with the same name in the automatically generated class ConsoleApplication1.Program+<>c__DisplayClass1> . You can use normal reflection to get the current value of this field by setting the right side of the binary expression in MemberExpression .

 var testValue = "hello"; var expr = (Expression<Func<string, bool>>) (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")); 

Alternatively, you can change your variable to a constant.

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

Instead of doing it yourself, check out PartialEvaluator from Matt Warren . It replaces all references to constants with the constants themselves.

0
source

All Articles