В 4.0 это намного проще благодаря поддержке операций с блоками в дереве (хотя и не в компиляторе выражений C #).
Однако вы могли бы сделать это, используя тот факт, что StringBuilder
предоставляет «свободный» API; поэтому вместо Action<T,StringBuilder>
у вас есть Func<T,StringBuilder,StringBuilder>
- как показано ниже (обратите внимание, что фактический синтаксис для выражения этих выражений идентичен в этом случае):
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; }
}
Конечно, возможно можно проверять деревья и излучать IL вручную (возможно, DynamicMethod
), но вам придется принять некоторые решения об ограничении сложности. Для кода в представленном виде я мог бы сделать это за разумное время (все еще не тривиально), но если вы ожидаете, что что-то более сложное, Expression
будет более жарким