C
C#2y ago
n8ta

Combine two Expression Func [Answered]

I have two Expression<Func<A,A>>. I want to combine them into a single Expression<Func<A,A>> that runs the output of the first through the second. How can I do that?
13 Replies
Thinker
Thinker2y ago
Couldn't you create a new expression which is the equivalent of (x) => b(a(x))?
n8ta
n8ta2y ago
I would like to combine the expressions programatically as opposed to writing the combo by hand. @thinker227
Thinker
Thinker2y ago
hold on
Anar
Anar2y ago
Expression<Func<T, T>> chain = x => e2.Compile()(e1.Compile()(x));
Expression<Func<T, T>> chain = x => e2.Compile()(e1.Compile()(x));
Maaaybe this?
n8ta
n8ta2y ago
Can't compile ahead of time that's done later in the process This eventually becomes SQL. Needs to stay as a proper expression.
Anar
Anar2y ago
catlurk Never mind then.
Thinker
Thinker2y ago
This works
Expression<Func<int, int>> a = (int x) => x - 2;
Expression<Func<int, int>> b = (int x) => x * 2;

var param = Expression.Parameter(typeof(int), "x");
var c = Expression.Lambda<Func<int, int>>(Expression.Invoke(a, Expression.Invoke(b, param)), param);

var func = c.Compile();
int i = func(7);
Expression<Func<int, int>> a = (int x) => x - 2;
Expression<Func<int, int>> b = (int x) => x * 2;

var param = Expression.Parameter(typeof(int), "x");
var c = Expression.Lambda<Func<int, int>>(Expression.Invoke(a, Expression.Invoke(b, param)), param);

var func = c.Compile();
int i = func(7);
n8ta
n8ta2y ago
Testing My case is actually A->B and B->B so I need to adapt it slightly Okay able to run yours as is. thanks you! Working on modifying now @thinker227 any idea what I might being doing wrong here?
Expression<Func<List<int>, int>> a = x => x[0];
Expression<Func<int, int>> b = x => x * 2;

var param = Expression.Parameter(typeof(int), "x");
var listParam = Expression.Parameter(typeof(List<int>), "x");

var c = Expression.Lambda<Func<List<int>, int>>(
Expression.Invoke(a, Expression.Invoke(b, listParam)), param);

var func = c.Compile();
int i = func(new List<int>() {5,6,7});
Console.WriteLine(i);
Expression<Func<List<int>, int>> a = x => x[0];
Expression<Func<int, int>> b = x => x * 2;

var param = Expression.Parameter(typeof(int), "x");
var listParam = Expression.Parameter(typeof(List<int>), "x");

var c = Expression.Lambda<Func<List<int>, int>>(
Expression.Invoke(a, Expression.Invoke(b, listParam)), param);

var func = c.Compile();
int i = func(new List<int>() {5,6,7});
Console.WriteLine(i);
System.ArgumentException: Expression of type 'System.Collections.Generic.List`1[System.Int32]' cannot be used for parameter of type 'System.Int32'
Thinker
Thinker2y ago
I think you only need one param The lambda you're expecting is a Func<List<int>, int> so you can't pass in a parameter of type int Replace param with listParam and it should work™️
n8ta
n8ta2y ago
Isn't the param when you call b different ? Since B accepts an int vs A accepting a List<int>
Thinker
Thinker2y ago
oh, yeah Right you have to do it in the reverse order, swap a and b
n8ta
n8ta2y ago
Okay sec testing Got it You are right we only need one param
Expression<Func<List<int>, int>> a = x => x[0];
Expression<Func<int, int>> b = x => x * 2;

var param = Expression.Parameter(typeof(int), "x");
var listParam = Expression.Parameter(typeof(List<int>), "x");

var interMediate = Expression.Invoke(a, listParam);

var c = Expression.Lambda<Func<List<int>, int>>(Expression.Invoke(b, interMediate), listParam);

var func = c.Compile();
int i = func(new List<int>() {5,6,7});
Console.WriteLine(i);
Expression<Func<List<int>, int>> a = x => x[0];
Expression<Func<int, int>> b = x => x * 2;

var param = Expression.Parameter(typeof(int), "x");
var listParam = Expression.Parameter(typeof(List<int>), "x");

var interMediate = Expression.Invoke(a, listParam);

var c = Expression.Lambda<Func<List<int>, int>>(Expression.Invoke(b, interMediate), listParam);

var func = c.Compile();
int i = func(new List<int>() {5,6,7});
Console.WriteLine(i);
$ 10 Thank you for the help! Now I just gotta convert this to my real types haha should be ez
Accord
Accord2y ago
✅ This post has been marked as answered!