In 4.0 this is much easier thanks to the support for block operations in the tree (although not in the C# expression compiler).
However, you could do this by exploiting the fact that StringBuilder
exposes a "fluent" API; so instead of Action<T,StringBuilder>
you have a Func<T,StringBuilder,StringBuilder>
- like below (note that the actual syntax for expressing these expressions is identical in this case):
class Program
{
static void Main()
{
Foo(new MyType { Name = "abc", Description = "def" });
}
static void Foo<T>(T val) where T : IMyType
{
var expressions = new Expression<Func<T, StringBuilder, StringBuilder>>[] {
(t, sb) => sb.Append(t.Name),
(t, sb) => sb.Append(", "),
(t, sb) => sb.Append(t.Description)
};
var tparam = Expression.Parameter(typeof(T), "t");
var sbparam = Expression.Parameter(typeof(StringBuilder), "sb");
Expression body = sbparam;
for (int i = 0; i < expressions.Length; i++)
{
body = Expression.Invoke(expressions[i], tparam, body);
}
var func = Expression.Lambda<Func<T, StringBuilder, StringBuilder>>(
body, tparam, sbparam).Compile();
// now test it
StringBuilder sbInst = new StringBuilder();
func(val, sbInst);
Console.WriteLine(sbInst.ToString());
}
}
public class MyType : IMyType
{
public string Name { get; set; }
public string Description { get; set; }
}
interface IMyType
{
string Name { get; }
string Description { get; }
}
It is certainly possible to inspect the trees and emit IL manually (DynamicMethod
perhaps), but you would have to make some decisions about limiting the complexity. For the code as presented I could do it in reasonable time (still not trivial), but if you expect anything more complex Expression
is more your fried.
Expression<Action<T, StringBuilder>> combinedExperssion = expr1 + expr2 + expr3;
? – Ordination