I have built my own SQL Query builder that breaks apart an Expression, however, I'm having an issue trying to get the value of string defined in the same function as the lambda expression.
Here is what I am trying to do in console app:
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 it subclasses from ExpressionVisitor, and I override the VisitMember. I found that a string defined in at the base Console level will come back as:
Node.Expression.NodeType == ExpressionType.Constant
The Node.Expression passes back properties of:
CanReduce = false
DebugView = ".Constant<ConsoleApplication1.Program+<>c__DisplayClass1>(ConsoleApplication1.Program+<>c__DisplayClass1)"
NodeType = Constant
Type = System.Type {System.RunetimeType}
Value = {ConsoleApplication1.Program}
The Node.Expression.Value contains:
testValue = "Test" (Type: string)
How do I get this value? I've tried several things, like:
var memberType = node.Expression.Type.DeclaringType;
This passes back a ConsoleApplication1.Program type.
However, when I do:
memberType.GetProperty("testValue"); // Declaring Type from Expression
It passes back null.
The above methods work fine if I place the lambda "strings" in a class, but doesn't work if they string is defined in the console function.
Can anyone tell me how to get the string value if it's defined at the function level of the lambda?
EDITED: Added 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 app example to show what works and what doesn't.
The lambda in your example has "closed over" the testValue variable, meaning the compiler has captured it as a field of the same name in an automatically generated class called ConsoleApplication1.Program+<>c__DisplayClass1>. You can use normal reflection to get the current value of that field by casting the right hand-side of the binary expression into a 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 into 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"));
Instead of doing this by yourself, have a look at PartialEvaluator from Matt Warren. It replaces all references to constants with the constants themselves.
Related
I would like to know if it is possible to create an instance of a type known only at runtime and assign values to the properties of this instance by using compiled expressions and if so how it is to be done.
I have a generic class with a method which accepts an instance of T and returns a copy. T is only known at runtime or rather is user/consumer defined. I know how to do so with reflection (assuming it has an empty constructor in this example and without exception handling or null checks for simplification).
public class MyClass<T>
{
public T CreateCopy(T source)
{
var type = typeof(T);
var copy = type.GetConstructor(Type.EmptyTypes).Invoke(null);
foreach(var pi in type.GetProperties())
{
pi.SetValue(copy, pi.GetValue(source));
}
return copy;
}
}
Reflection is quite expensive and after some digging i found an option to at least create an instance of T with compiled expressions.
var type = typeof(T);
Expression.Lambda<Func<T>>(Expression
.New(type.GetConstructor(Type.EmptyTypes)
?? throw new InvalidOperationException(
$"Type has to have an empty public constructor. {type.Name}")))
.Compile();
After some benchmarking i have found out that it performs around 6 times faster than the CreateCopy(...) method. The thing is that i do not know which type will be passed in as a generic and how many properties it will have.
Is there a way to do all of the operations from CreateCopy(...) method with compiled expressions?
Ihave looked into Expression.Asign, Expression.MemberInit but i am not able to find anything appropriate. The problem with Expression.MemberInit ist that it expects to have an Expresssion.Bind and Expression.Constant but i cant get the values of the properties from the passed instance of T into it. Is there a way?
Thank you.
P.S. So i am looking for something like:
var type = typeof(T);
var propertyInfos = type.GetProperties();
var ctor = Expression.New(type.GetConstructor(Type.EmptyTypes));
var e = Expression.Lambda<Func<T, T>>(Expression
.MemberInit(ctor, propertyInfos.Select(pi =>
Expression.Bind(pi, Expression.Constant(pi.GetValue(source)))))).Compile();
You are almost there. What you need is to define a parameter and then assign the properties with property access expression like below :
public static T Express<T>(T source)
{
var parameter = Expression.Parameter(typeof(T), "source");
var type = typeof(T);
var ctor = Expression
.New(type.GetConstructor(Type.EmptyTypes));
var propertyInfos = type.GetProperties();
var e = Expression
.Lambda<Func<T, T>>(
Expression
.MemberInit(ctor, propertyInfos.Select(pi =>
Expression.Bind(pi, CanBeAssigned(pi.PropertyType)
? (Expression)Expression.Property(parameter, pi.Name)
: Expression.Call(typeof(Program).GetMethod(nameof(Express))
.MakeGenericMethod(pi.PropertyType),
Expression.Property(parameter, pi.Name)
))
)),
parameter
);
var x = e.Compile();
var z = x(source);
return z;
}
public static bool CanBeAssigned(Type t)
{
return t.IsValueType || t.Name == "String"; // this might need some improvements
}
I'm creating a simple way to get the Name and Value of Expressions in C#. However, I found a case I cannot figure out. See the code below:
public void GetValue_Object_TIn_Property_Test()
{
string val = "value";
var tuple = Tuple.Create(new object(), val);
Expression<Func<object, string>> expression = x => tuple.Item2;
Assert.AreEqual(val, expression.GetValue());
}
The .GetValue() method is my extension method.
Basically this expression-tree consists of a LambdaExpression, two MemberExpressions and a ConstantExpression, in that order.
When I try to get the name of tuple.Item2 I get memberExpression.Member.Name from the last MemberExpression. This gives me "tuple" instead of "Item2". How can I get "Item2" instead?
Also, when I try to get the value of the expression, I get the entire tuple instead of Item2. I'm using the following method to get the value:
public override bool TryGetValue(
MemberExpression memberExpression,
out T value
) {
value = default(T);
bool success = false;
var fieldInfo = memberExpression.Member as FieldInfo;
if (success = (fieldInfo != null))
{
var valueObj = fieldInfo.GetValue(expression.Value);
if (success = (valueObj is T || valueObj == null))
{
value = (T)valueObj;
}
}
return success;
}
Where the MemberExpression again is the last MemberExpression. What am I doing wrong here? What is the exact case I am missing?
Thank you in advance
Actually, the tree is a LambdaExpression whose Body is a PropertyExpression that has a Member field with a Name of "Item2" and an Expression that is aFieldExpression for getting the value of tuple. Note that PropertyExpression and FieldExpression are internal types that inherit from MemberExpression.
So you need to get the (Body as MemberExpression).Member.Name instead of the Body.Expression.Member.Name.
Think of the tree as MemberExpression(get Member:Item2 from Expression:MemberExpression(get Member:tuple from Expression:[surrounding class])).
Have you used LINQPad? It's Dump() command can show you this and more.
UPDATE: This question was marked as duplicated, but although I understand the issue with the code, I don't have a solution. Is it possible for the code to work by only changing the method bodies and not the method signatures?
I'm tying to wrap my head around Expression and Func, while trying to build a class like the following:
public class Test<TBase>
{
private IList<Expression<Func<object, object>>> _expressions = new List<Expression<Func<object, object>>>();
public void AddExpression<T>(Expression<Func<TBase, T>> e)
{
_expressions.Add(e);
}
public void AddExpression<T1, T2>(Expression<Func<T1, T2>> e)
{
_expressions.Add(e);
}
}
I need/would like to keep a list of expressions, where the types inside the Func may vary. I though the code above would work but it doesn't. It fails with:
Cannot convert from 'Expression<Func<TBase, T>>' to 'Expression<Func<object, object>>'
Cannot convert from 'Expression<Func<T1, T2>>' to 'Expression<Func<object, object>>'
Resharper says:
Argument type 'Expression<Func<TBase, T>>' is not assignable to parameter type 'Expression<Func<object, object>>'
Argument type 'Expression<Func<T1, T2>>' is not assignable to parameter type 'Expression<Func<object, object>>'
Is it possible for the code to work by only changing the method bodies and not the method signatures?
UPDATE: This question was marked as duplicated, but although I understand the issue with the code, I don't have a solution. Is it possible for the code to work by only changing the method bodies and not the method signatures?
Yes, you can keep the method signatures, but you'll have to rewrite the expressions...
Like this:
public void AddExpression<T1, T2>(Expression<Func<T1, T2>> e)
{
var originalParameter = e.Parameters[0];
// object par1
var parameter = Expression.Parameter(typeof(object), originalParameter.Name);
// T1 var1
var variable = Expression.Variable(typeof(T1), "var1");
// (T1)par1
var cast1 = Expression.Convert(parameter, typeof(T1));
// var1 = (T1)par1;
var assign1 = Expression.Assign(variable, cast1);
// The original body of the expression, with originalParameter replaced with var1
var body = new SimpleParameterReplacer(originalParameter, variable).Visit(e.Body);
// (object)body (a cast to object, necessary in the case T2 is a value type. If it is a reference type it isn't necessary)
var cast2 = Expression.Convert(body, typeof(object));
// T1 var2; var1 = (T1)par1; (object)body;
// (the return statement is implicit)
var block = Expression.Block(new[] { variable }, assign1, cast2);
var e2 = Expression.Lambda<Func<object, object>>(block, parameter);
_expressions.Add(e2);
}
I'm using the SimpleParameterReplacer from another response I gave some time ago.
In the end a (T1 x) => x.Something (with x.Something being a T2) is transformed in:
(object x) =>
{
var var1 = (T1)x;
return (object)var1.Something;
}
I have the following code :
var factory = Expression.Parameter(typeof(FooFactory));
var fooInstance = Expression.Variable(typeof(Foo));
var factoryCall = Expression.Call(factory, "Instantiate", new[] { typeof(Foo) });
Expression.Assign(fooInstance, factoryCall);
List<Expression> expressions = new List<Expression>();
// TODO : add more expressions to do things on fooInstance ...//
expressions.Add(fooInstance); //return fooInstance
Expression finalExpr = Expression.Block(new[] { fooInstance }, expressions);
What it is supposed to do :
Use factory given as parameter and call Instantiate<T>() method on it.
Store the returned value (a foo instance) to a local variable.
Do things on that local variable (missing in that example)
Return the instance
The problem is : when I compile and call the expression, Instantiate() is never called. The value returned is always null :
var method = Expression.Lambda<Func<FooFactory, Foo>>(finalExpr, factory).Compile();
Foo foo = method(new FooFactory()); //foo is null :(
My bad. I forget that Expression.Assign() returns an expression.
When doing this instead, it works beautifully :
List<Expression> expressions = new List<Expression>();
expressions.Add(Expression.Assign(fooInstance, call));
Thanks Luaan for the tip.
What is the best way to check if constant is null in Expression Trees?
// Method to call (Regex.IsMatch)
MethodInfo isMatchMethod = typeof(Regex).GetMethod("IsMatch", new[] { typeof(string), typeof(string), typeof(RegexOptions) });
// The member you want to evaluate: (x => x.<property_name>)
var member = Expression.Property(param, propertyName);
// The value you want to evaluate
var constant = Expression.Convert(Expression.Constant(value), type);
// How to check if constant is null???
var expr = Expression.Call(isMatchMethod, member, constant, Expression.Constant(RegexOptions.IgnoreCase));
// Doesn't work
// Expression notNullConstant = value != null ? constant : Expression.Convert(Expression.Constant(string.Empty), type);
//var expr = Expression.Call(isMatchMethod, member, notNullConstant, Expression.Constant(RegexOptions.IgnoreCase));
Not sure what the problem is. You can translate a ?? b literally into a tree with Expression.Coalesce. If in doubt compile an expression with the C# compiler and look at what it did.
http://tryroslyn.azurewebsites.net/#f:r/K4Zwlgdg5gBAygTxAFwKYFsDcAoUlaIoYB0AMpAI7ECiAHgA4BOqI4A9hCDvcAEYA2YAMYwh/AIasYAYRgBvbDCUweA4TABubMABMYAWQAUASnmLlFukxbsIAHgBiwCELspG+AHyeY4mAF4YEwCfACJQmAB+SJhwnAsAX2wEoAA=
Meanwhile you have asked how to compile ?:. The answer is the same: Simply decompile existing code to see what is being output. Use Expression.Condition.