Я думаю, что понимаю, что вы пытаетесь сделать, порядок может быть неправильным (если так просто переключить положение f1 и f2 на 4-й строке).
Expression<Func<string, string>> f1 = (s) => "hello" + s;
Expression<Func<string, string>> f2 = (s) => s + s;
var parameter = Expression.Parameter(typeof(string), "p1");
Expression<Func<string, string>> ffinal = Expression.Lambda<Func<string, string>>(Expression.Invoke(f1, Expression.Invoke(f2, parameter)), parameter);
Console.WriteLine(ffinal.ToString());
Console.WriteLine(ffinal.Compile()("123"));
при вызове ffinal он принимает строки, переданных в, вызывает f2 и результат, который получает передаются в f1, поэтому печатная строка hello123123
также интерес входе выражение в строку дает это
p1 => Invoke(s => ("hello" + s), Invoke(s => (s + s), p1))
стоит отметить, что это в основном делает это: '(p1) => f1 (f2 (p1))', если вы беспокоитесь об эффективности, вы могли бы получить тело каждой функции лямбда заменить параметры и скомпилируйте его в это: '(p1) =>" hello "+ (p1 + p1)", который может быть более эффективным, но немного сложнее, чем мой один лайнер. – Eluvatar