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.
Related
I'm stuck on a lambda with a single int parameter and a bool return value:
Expression<Func<int, bool>> myFunc = x => x == 5;
First, I tried this that returns a new Func that I can't make sense of; I was expecting a true boolean value:
var boolResult = Expression.Lambda(myFunc).Compile().DynamicInvoke(5);
Then I tried to explictly set the function parameters and return type instead:
var param = Expression.Parameter(typeof(int), "x");
var fn = Expression.Lambda<Func<int, bool>> (myFunc, param).Compile();
, but this throws an error:
System.ArgumentException : Expression of type
'System.Func`2[System.Int32,System.Boolean]' cannot be used for return
type 'System.Boolean'
Which is weird, but I tried to convert the expression:
var fn = Expression.Lambda<Func<int, bool>> (
Expression.Convert(myFunc,
typeof(Func<int, bool>))
, param).Compile();
var boolResult = fn.Invoke(5);
, this however did not help and gives the same error:
System.ArgumentException : Expression of type
'System.Func`2[System.Int32,System.Boolean]' cannot be used for return
type 'System.Boolean'
Any idea of what I'm doing wrong here?
The error in your dynamic invocation code is the way in which you construct your lambda. When you pass myFunc as expression, you get a lambda that returns Func<int,bool>.
If you want to make a new LambdaExpression that takes int and return bool, you could harvest Body and Parameters of your myFunc object, like this:
var b = Expression.Lambda(myFunc.Body, myFunc.Parameters).Compile().DynamicInvoke(5);
or, since myFunc is already a LambdaExpression, you could compile it directly:
var c = myFunc.Compile().DynamicInvoke(6);
Demo.
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;
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.
I'm trying to figure out how to put all the pieces together, and would appreciate a concrete source code sample for a simple case to start with.
Consider the following C# code:
Func<int, int, int> f = (x, y) => x + y;
I can produce an equivalent function at runtime using expression trees as follows:
var x = Expression.Parameter(typeof(int), "x");
var y = Expression.Parameter(typeof(int), "y");
Func<int, int, int> f =
Expression.Lambda<Func<int, int, int>>(
Expression.Add(x, y),
new[] { x, y }
).Compile();
Now given the following lambda:
Func<dynamic, dynamic, dynamic> f = (x, y) => x + y;
how would I generate the equivalent using expression trees (and, presumably, Expression.Dynamic)?
You can create an expression tree that represents a dynamic C# addition expression by passing the CallSiteBinder for a dynamic C# addition expression into Expression.Dynamic. You can discover the code to create the Binder by running Reflector on the original dynamic expression. Your example would go something like this:
var x = Expression.Parameter(typeof(object), "x");
var y = Expression.Parameter(typeof(object), "y");
var binder = Binder.BinaryOperation(
CSharpBinderFlags.None, ExpressionType.Add, typeof(Program),
new CSharpArgumentInfo[] {
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
Func<dynamic, dynamic, dynamic> f =
Expression.Lambda<Func<object, object, object>>(
Expression.Dynamic(binder, typeof(object), x, y),
new[] { x, y }
).Compile();
You cannot do that because an expression tree "May not contain a dynamic operation".
The following will not compile, because of the + operation, for example, and you are trying to build an expression tree that violates that rule:
Expression<Func<dynamic, dynamic, dynamic>> f = (x, y) => x + y;
If you were not doing an Add operation you could get away with it.
See How to create an Expression<Func<dynamic, dynamic>> - Or is it a bug? for more information.
Edit:
This is as close as I can get, by defining my own Add method that takes dynamic parameters and returns a dynamic result.
class Program
{
static void Main(string[] args)
{
var x = Expression.Parameter(typeof(object), "x");
var y = Expression.Parameter(typeof(object), "y");
Func<dynamic, dynamic, dynamic> f =
Expression.Lambda<Func<dynamic, dynamic, dynamic>>(
Expression.Call(typeof(Program), "Add", null, x, y),
new[] { x, y }
).Compile();
Console.WriteLine(f(5, 2));
Console.ReadKey();
}
public static dynamic Add(dynamic x, dynamic y)
{
return x + y;
}
}
Very interesting. I guess it's impossible for the same reason the following does not compile:
Expression<Func<dynamic, dynamic, int>> func = (p1, p2) => p1 + p2;
It's a compiler error CS1963 (which doesn't seem to be documented by MS):
error CS1963: An expression tree may not contain a dynamic operation
During my work with expression trees for a few days now, I came across something that I find difficult to understand; hopefully someone will be able so shed some light here.
If you code Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x; the compiler will complain and you won't get anywhere. However, it seems that if you create one such expression through a method then the compiler seems to be happy about it and the resulting app works. This doesn't make sense, so I'm wondering what goes on behind the curtains.
I suppose that, under the hood, the expression returned by ConvertExpression is perhaps of type Expression<Func<object, object>>, which is a valid type, but it puzzles me that I can't use Expression<Func<dynamic, dynamic>> type in a declaration and yet I can use it as the return type of a method. See an example below.
Thanks a lot!
public class ExpressionExample
{
public void Main()
{
// Doesn't compile:
//Expression<Func<dynamic, dynamic>> expr1 = x => 2 * x;
// Compiles and works - OK
Expression<Func<double, double>> expr2 = x => 2 * x;
Func<double, double> func2 = (Func<double, double>)expr2.Compile();
Console.WriteLine(func2(5.0).ToString()); // Outputs 10
// Compiles and works - ??? This is the confusing block...
Expression<Func<dynamic, dynamic>> expr3 = ConvertExpression(expr2);
Func<dynamic, dynamic> func3 = (Func<dynamic, dynamic>)expr3.Compile();
Console.WriteLine(func3(5.0).ToString()); // Outputs 10
// Side note: compiles and works:
Expression<Func<object, object>> expr4 = x => double.Parse(2.ToString()) * double.Parse(x.ToString());
Func<object, object> func4 = (Func<object, object>)expr4.Compile();
Console.WriteLine(func4(5.0).ToString()); // Outputs 10
}
private Expression<Func<dynamic, dynamic>> ConvertExpression<TInput, TOutput>(Expression<Func<TInput, TOutput>> expression)
{
Expression<Func<object, TInput>> convertToInput = value => (TInput)value;
// The following doesn't compile: var input = Expression.Parameter(typeof(dynamic), "input");
var input = Expression.Parameter(typeof(object), "input");
Expression<Func<TOutput, dynamic>> convertToOutput = value => (dynamic)value;
var body = Expression.Invoke(convertToOutput, Expression.Invoke(expression, Expression.Invoke(convertToInput, input)));
var lambda = Expression.Lambda<Func<dynamic, dynamic>>(body, input);
return lambda;
}
}
I suppose that, under the hood, the expression returned by ConvertExpression is perhaps of type Expression<Func<object, object>>, which is a valid type
Correct.
I can't use Expression<Func<dynamic, dynamic>> type in a declaration and yet I can use it as the return type of a method.
This portion of the statement is incorrect. As you note in your example, it is perfectly legal to use that type in the declaration of a local variable.
The bit that is not legal is the execution of a dynamic operation inside a lambda that is being converted to an expression tree type. The specific expression tree type is irrelevant; what matters is that the operation is dynamic.
The compiler error I got when I tried your code was "error CS1963: An expression tree may not contain a dynamic operation". I changed the problem line to Expression<Func<dynamic, dynamic>> expr1 = x => x; (removing the "operation" from the lambda) and it worked! So you are allowed to have dynamics in expressions, but you can't actually perform any "operations" on them. Not very helpful, I know. In my testing, even .ToString() counts as an operation.