在 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
更麻烦了。