If I want to replace this anonymous method:
Func<int, int> f = delegate(int i)
{
return i + 1;
};
with an expression tree, it would like this:
ParameterExpression i = Expression.Parameter(typeof(int), "i");
Expression one = Expression.Constant(1, typeof(int));
Expression body = Expression.Add(i, one);
Func<int, int> f = Expression.Lambda<Func<int, int>>(body, i).Compile();
(I know: an expression tree will secretly dynamically create another anymous method, but that is not the point).
Now I want to replace the following method with an expression tree:
Func<int, int> f = delegate(int i)
{
Debug.WriteLine("Inside the function!");
return i + 1;
};
Is there a way and how do I do this?
Yes, you can do the replacement. The structure of your current expression looks like this:
Expression.Lambda
Expression.Add
Expression.Parameter("a")
Expression.Constant(1)
the structure of the new expression will look like this:
Expression.Lambda
Expression.BlockExpression
Expression.Call
Expression.Constant("Inside the function!")
MedhodInfo(Debug.WriteLine)
Expression.Add
Expression.Parameter("a")
Expression.Constant(1)
You will need to provide MedhodInfo for the Debug.WriteLine to the Call expression. The last expression in the block (i.e. a+1) will be considered block's return expression.
Related
I can print a lambda expression like this
Expression<Func<double,double>> expr = x => x * x;
string s = expr.ToString(); // "x => (x * x)"
However if
Func<double, double> function = x => x * x;
Then how can I generate the Expression<Func<double,double>> to produce the same result ? Expression constructor is internal and there is no implicit conversion between Func types and Expression of them.
You can't.
When you write:
Expression<Action<int>> e = x => Console.WriteLine(x);
The compiler emits (simplified):
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "x");
MethodInfo method = typeof(Console).GetMethod("WriteLine", new[] { typeof(object) });
MethodCallExpression body = Expression.Call(null, method, parameterExpression);
Expression<Action<int>> e = Expression.Lambda<Action<int>>(body, parameterExpression);
See how it actually emits code which re-creates the expression tree at runtime?
In contrast, when you write:
Action<int> a = x => Console.WriteLine(x);
The compiler emits (simplified)
internal void GeneratedMethod(int x)
{
Console.WriteLine(x);
}
...
Action<int> a = new Action<int>(GeneratedMethod);
See the difference? The runtime simply isn't able to take a compiled method and create an expression tree for it.
The only way that expression trees get constructed is using the methods on the Expression class to build it up out of its various parts. If you use a lambda, the compiler cleverly emits code which does this at runtime. However you can't start with a compiled method.
See the examples on SharpLab.
A C# lambda expression (of type System.Linq.Expressions.Expression<TDelegate>) in code:
Expression<Func<Something, bool>> predicate = s => s.SomeProperty == 12;
To create a similar instance of System.Linq.Expressions.Expression:
var parameter = Expression.Parameter(typeof(Something), "s");
var property = Expression.Property(parameter, typeof(Something).GetProperty("SomeProperty"));
var constant = Expression.Constant(12);
var expression = Expression.Equal(property, constant);
Is there a way to declare expression given only the predicate? So without building the expression tree step by step in code, but having the compiler infer it from a lambda expression.
var expression = Expression.FromLambda<Something>(s => s.SomeProperty == 12);
Sure, just grab the body of the lambda expression, like so:
Expression FromLambda(Expression<Func<Something, bool>> lambda)
{
return lambda.Body;
}
Then you can use it like so:
var expression = FromLambda(s => s.SomeProperty == 12);
Just return the expression
Expression<Func<T, bool>> FromLambda<T>(Expression<Func<T, bool>> lambda) {
return lambda;
}
And use as desired
var expression = FromLambda<Something>(s => s.SomeProperty == 12);
This however is not very flexible and targets just this scenario. You would need to create methods for any other delegate you want to use.
If I have linq which looks like this:
!new List<int>{1,2,3}.Contains(x.someColumn)
And I want to translate this to Expression, so something like this:
var mInfo = typeof (List<int>).GetMethod("Contains", new Type[] {typeof (int)});
var lst = new List<int>();
foreach (var a in f.Value.Split(','))
{
var b = int.Parse(a);
lst.Add(b);
}
var lConst = Expression.Constant(iList);
var b = Expression.Call(lConst,mInfo, propertyReference);
return Expression.Lambda<Func<TmpResult, bool>>(b, param);
This will work like Contains, but how to change it to be like !Contains?
If I try to wrap it with Expression.Not I got error:
The unary operator Not is not defined for the type System.Func
You can use the Expression.Not method over the body of the lambda expression:
return Expression.Lambda<Func<TmpResult, bool>>(Expression.Not(b), param);
// ^ negate body
Since a lambda-expression is a function, you can not negate the lambda expression itself, you can only negate the result of the lambda expression.
I know I am asking the bizarre but just for kicks, is it possible to get the MethodInfo for a lambda expression?
I am after something like this:
(Func<int, string>(i => i.ToString())).MethodInfo
UPDATE
I want to get the method info regardless of whether the body of the lamda is a method call expression or not, i.e. regardless of what type of expression the body of the lambda is.
So, for e.g.
This might work.
var intExpression = Expression.Constant(2);
Expression<Func<int, Dog>> conversionExpression = i => Program.GetNewDog(i);
var convertExpression5 = Expression.ConvertChecked(intExpression, typeof(Dog), ((MethodCallExpression)(conversionExpression.Body)).Method);
class Program
{
static Dog GetNewDog(int i)
{
return new Dog();
}
}
But I want even this to work:
var intExpression = Expression.Constant(2);
Expression<Func<int, Dog>> conversionExpression = i => new Dog();
var convertExpression5 = Expression.ConvertChecked(intExpression, typeof(Dog), /*...???... */);
You are quite close :)
You can do something like this:
MethodInfo meth = (new Func<int, string>(i => i.ToString())).Method;
Note: This might have problems if you have multiple 'subscribers' to a delegate instance.
Reference: https://learn.microsoft.com/en-us/dotnet/api/system.delegate.method
Using the System.Linq.Expressions namespace, you can do the following.
Expression<Func<int, string>> expression = i => i.ToString();
MethodInfo method = ((MethodCallExpression)expression.Body).Method;
Suppose I have something like
Expression<Func<SomeType, DateTime>> left = x => x.SomeDateProperty;
Expression<Func<SomeType, DateTime>> right = x => dateTimeConstant;
var binaryExpression = Expression.GreaterThan(left, right);
Expression<Func<SomeType, bool>> predicate =
x => x.SomeDateProperty> dateTimeConstant;
1) How can I replace the right hand of the assignment of the last line with something that uses the binaryExpression instead? var predicate = x => binaryExpression; doesn't work.
2) The right is always a constant, not necessarily DateTime.Now. Could it be of some simpler Expression type? For instance, it doesn't depend on SomeType, it is just a constant.
3) If I have the GreaterThan as a string, is there a way to get from this string to the method with the same name in Expression? In general, if the name of the comparison method is given as a string, how can I go from the string to actually calling the method with the same name on the Expression class?
It has to work with LINQ to Entities, if it matters.
1 and 2: You need to build the expression tree manually to do this, the compiler cannot help because it only constructs ready-made expressions that represent functions in their entirety. That's not useful when you want to build functions piece by piece.
Here's one straightforward way to build the expression you want:
var argument = Expression.Parameter(typeof(SomeType));
var left = Expression.Property(argument, "SomeDateProperty");
var right = Expression.Constant(DateTime.Now);
var predicate = Expression.Lambda<Func<SomeType, bool>>(
Expression.GreaterThan(left, right),
new[] { argument }
);
You can take this for a test drive with
var param = new SomeType {
SomeDateProperty = DateTime.Now.Add(TimeSpan.FromHours(-1))
};
Console.WriteLine(predicate.Compile()(param)); // "False"
3: Since in all likelihood the number of possible choices for your binary predicate will be quite small, you could do this with a dictionary:
var wordToExpression =
new Dictionary<string, Func<Expression, Expression, BinaryExpression>>
{
{ "GreaterThan", Expression.GreaterThan },
// etc
};
Then, instead of hardcoding Expression.GreaterThan in the first snippet you would do something like wordToExpression["GreaterThan"](left, right).
Of course this can also be done the standard way with reflection.
When you use GreaterThan, you need to specify the expression bodies, not the lambda itself. Unfortunately, there is a complication: the x in the two expressions is not the same.
In this particular case, you could just about get away with this, because the second expression does not use x
So; your "1" and "2" should be answered by:
var binaryExpression = Expression.GreaterThan(left.Body, right.Body);
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression,
left.Parameters);
However, to handle this in the general case, you must rewrite on of the expressions, to fix-up the parameters:
var binaryExpression = Expression.GreaterThan(left.Body,
new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body));
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression,
left.Parameters);
with:
public class SwapVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
For your "3"; there is nothing inbuilt for that; you could use reflection, though:
string method = "GreaterThan";
var op = typeof(Expression).GetMethod(method,
BindingFlags.Public | BindingFlags.Static,
null, new[] { typeof(Expression), typeof(Expression) }, null);
var rightBody = new SwapVisitor(right.Parameters[0],
left.Parameters[0]).Visit(right.Body);
var exp = (Expression)op.Invoke(null, new object[] { left.Body, rightBody });
var lambda = Expression.Lambda<Func<SomeType, bool>>(exp, left.Parameters);