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
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.
I'm just learning about Expression and their expression-trees to use them with IronPython (but that's irrelevant for now).
What I'm trying to do is, creating an expression tree like the following lambda:
Func<T, int, string> func = (s,t) => s + t;
My current function is this:
public static Expression<Func<T, int, string>> StringConcatSelector<T>()
{
var parameterParam = Expression.Parameter(typeof(T), "x");
var paramToString = typeof(T).GetMethods().FirstOrDefault(s=>s.Name=="ToString");
var parameter = Expression.Call(parameterParam, paramToString);
var intParameterParam = Expression.Parameter(typeof(int), "s");
var intParameterToString = typeof(int).GetMethods().FirstOrDefault(s => s.Name == "ToString");
var intParameter = Expression.Call(intParameterParam, intParameterToString);
var stringConcat = typeof(string).GetMethods().FirstOrDefault(s => s.Name == "Concat");
var result = Expression.Call(stringConcat, parameter, intParameter);
return Expression.Lambda<Func<T, int, string>>
(result, parameterParam, intParameterParam);
}
the Expression.Callof String.Concat won't work this way, because of invalid parameter-count.
So I think I need something like:
create a List<string>-variable-expression
add both values to the list
use String.Concatwith the list-expression.
Am I right?
If yes, how can I create a List-variable (or an Array), add both values to take it as parameter for my String.Concat?
String.Concat method has 11 (!) overloads, and you are taking a random one.
The most appropriate for your case is
public static String Concat(String str0, String str1)
which you can get by using the following Type.GetMethod overload
public MethodInfo GetMethod(string name, Type[] types)
where the types array represents the type of the method arguments:
var stringConcat = typeof(string).GetMethod("Concat",
new[] { typeof(string), typeof(string) });
Let us say I have the following two expressions:
Expression<Func<T, IEnumerable<TNested>>> collectionSelector;
Expression<Func<IEnumerable<TNested>, TNested>> elementSelector;
Is there a way to "combine" these in order to form the below: (?)
Expression<Func<T, TNested>> selector;
EDIT:
Performance is very critical, so I would appreciate an optimal solution with very little overhead, if possible.
Many Thanks!
static Expression<Func<A, C>> Foo<A, B, C>(
Expression<Func<B, C>> f,
Expression<Func<A, B>> g)
{
var x = Expression.Parameter(typeof(A));
return Expression.Lambda<Func<A, C>>(
Expression.Invoke(f, Expression.Invoke(g, x)), x);
}
Unfortunately, I cannot access to computer ( it is bad solution in performance terms). Actually, I think that you can optimize code via call Expression.
Another way seems like that(usage auxiliary function):
Func<A, C> Foo<A,B,C>(Func<B, C> f, Func<A, B> g)
{
return (A x) => f(g(x));
}
Then you should create pipeline Expression via call Expression with Foo function. Like that pseudo code:
var expr1 = get expresstion<B,C>
var expr2 = get Expression<A, B>
var foo = get method info of Foo method
specialize method with generic types A, B, C (via make generic method)
return Expression.Call(foo, expr1, expr2);
Another solution is to use ExpressionVisitor to replace the parameter in right expression with the whole left expression, in other words, embed the left one in the right one.
Expression visitor will be quite simple, add needed data to constructor, override one method and that's all.
internal sealed class ParameterReplaceVisitor : ExpressionVisitor
{
private readonly ParameterExpression _searched;
private readonly Expression _replaced;
public ParameterReplaceVisitor(ParameterExpression searched, Expression replaced)
{
if (searched == null)
throw new ArgumentNullException(nameof(searched));
if (replaced == null)
throw new ArgumentNullException(nameof(replaced));
_searched = searched;
_replaced = replaced;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == _searched)
return _replaced;
return base.VisitParameter(node);
}
}
It can be quite easily extended to handle collections of expressions in the constructor, but I kept it short.
Now, you just need to use it on the expression bodies and construct new lambda.
private static Expression<Func<TIn, TOut>> Merge<TIn, TInter, TOut>(Expression<Func<TIn, TInter>> left, Expression<Func<TInter, TOut>> right)
{
var merged = new ParameterReplaceVisitor(right.Parameters[0], left.Body).Visit(right.Body);
var lambda = Expression.Lambda<Func<TIn, TOut>>(merged, left.Parameters[0]);
return lambda;
}
I tested it on this code:
Expression<Func<string, int>> l = s => s.Length + 5;
Expression<Func<int, string>> r = i => i.ToString() + " something";
var merged = Merge(l, r);
var res = merged.Compile()("test");
and the result is as expected: 9 something.
EDIT:
If performance is your concern, why are you using expressions instead of plain Funcs? Then you could just invoke one after another. Are the expression trees later analyzed?
Expression<Func<TSourceType, TFinalType>> ChainExpressions<TSourceType, TIntermediaryType, TFinalType>(
Expression<Func<TSourceType, TIntermediaryType>> firstExpression,
Expression<Func<TIntermediaryType, TFinalType>> secondExpression
)
{
var sourceInput = Expression.Parameter(typeof(TSourceType));
var expressionForIntermediaryValue = Expression.Invoke(firstExpression, sourceInput);
var expressionToGetTypedIntermediaryValue = Expression.Convert(expressionForIntermediaryValue, typeof(TIntermediaryType));
var expressionForFinalValue = Expression.Invoke(secondExpression, expressionToGetTypedIntermediaryValue);
var expressionToGetTypedFinalValue = Expression.Convert(expressionForFinalValue, typeof(TFinalType));
var finalOutputExpression = Expression.Lambda(expressionToGetTypedFinalValue, sourceInput);
return (Expression<Func<TSourceType, TFinalType>>)finalOutputExpression;
}
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.
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.