如何将多个表达式组合成一个快速方法?
假设我有以下表达式:
Expression<Action<T, StringBuilder>> expr1 = (t, sb) => sb.Append(t.Name);
Expression<Action<T, StringBuilder>> expr2 = (t, sb) => sb.Append(", ");
Expression<Action<T, StringBuilder>> expr3 = (t, sb) => sb.Append(t.Description);
我希望能够将它们编译成相当于以下内容的方法/委托:
void Method(T t, StringBuilder sb)
{
sb.Append(t.Name);
sb.Append(", ");
sb.Append(t.Description);
}
解决这个问题的最佳方法是什么?我希望它能够表现良好,理想情况下性能与上述方法相当。
更新 那么,虽然看起来无法在 C#3 中直接执行此操作,但有没有办法将表达式转换为 IL,以便我可以将其与 System.Reflection.Emit 一起使用?
Suppose I have the following expressions:
Expression<Action<T, StringBuilder>> expr1 = (t, sb) => sb.Append(t.Name);
Expression<Action<T, StringBuilder>> expr2 = (t, sb) => sb.Append(", ");
Expression<Action<T, StringBuilder>> expr3 = (t, sb) => sb.Append(t.Description);
I'd like to be able to compile these into a method/delegate equivalent to the following:
void Method(T t, StringBuilder sb)
{
sb.Append(t.Name);
sb.Append(", ");
sb.Append(t.Description);
}
What is the best way to approach this? I'd like it to perform well, ideally with performance equivalent to the above method.
UPDATE
So, whilst it appears that there is no way to do this directly in C#3 is there a way to convert an expression to IL so that I can use it with System.Reflection.Emit?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不幸的是,在 .NET 3.5 中,您无法构建执行一系列任意操作的表达式。以下是支持的表达式列表:
。 NET 4 通过添加以下表达式来扩展此 API:
调试 .100).aspx" rel="nofollow noreferrer">Block 表达式特别有趣。
Unfortunately in .NET 3.5 you cannot build an expression which performs a series of arbitrary operations. Here's the list of supported expressions:
.NET 4 extends this API by adding the following expressions:
The Block expression is particularly interesting.
你可以,但这不是一个简单的任务。
当您有表达式类型的变量时,您可以检查其 Body 属性以查找表达式的数据结构。
您不能要求编译器为您编译它,因为它不会得到您想要的结果。您必须解析所有表达式的主体,并以某种方式将它们组合成一个方法,所有这些都是通过同时发出 IL (或者,如果您觉得 IL 太过分了,则通过生成 C# 并对其进行编译)。
正如 LINQ-to-SQL 将表达式编译为 SQL 查询一样,您也可以将表达式编译为您需要的任何内容。您将有很多工作要做,但您只需要实现您想要支持的内容即可。
在这个相当简单的例子中,我认为没有必要创建自己的 LINQ 提供程序。您可以只使用传递的表达式并从那里开始。但我怀疑你的申请比这更复杂一些。
You can, but it's not trivial task.
When you have a variable of type Expression, you can inspect its Body property to find the data structure of the expression.
You can't ask the compiler to compile it for you because it will not get the result that you want. You'll have to parse the bodies of all your expressions and somehow combine them into a single method, all by emitting IL at the same time (or, by producing C# and have that compiled if you feel IL is a step too far).
Just as LINQ-to-SQL compiles the expression to a SQL query, so can you compile your expressions into whatever you need. You'll have a lot of work ahead of you, but you only need to implement that what you want to support.
In this rather trivial case I don't think it's necessary to create your own LINQ provider. You could just work with the expression as passed and go from there. But I suspect your application is a bit more complicated than that.
在 4.0 中,由于支持树中的块操作(尽管在 C# 表达式编译器中不支持),这要容易得多。
但是,您可以通过利用
StringBuilder
公开“流畅”API 的事实来做到这一点;因此,您有一个Func
而不是Action
- 如下所示(请注意,表达这些表达式的实际语法是 在本例中是相同的):当然可能检查树并手动发出IL(也许
DynamicMethod
),但您必须做出一些决定关于限制复杂性。对于所呈现的代码,我可以在合理时间内完成它(仍然不简单),但如果您期望任何更复杂的表达式
更适合您油煎。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 ofAction<T,StringBuilder>
you have aFunc<T,StringBuilder,StringBuilder>
- like below (note that the actual syntax for expressing these expressions is identical in this case):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 complexExpression
is more your fried.您只能在 .NET 4 中执行此操作。抱歉,我不知道详细信息。
编辑:
如果您对 Reflection.Emit 感到满意,您可以发出一个按顺序调用这些表达式的方法。
另一种选择:
创建一个“do”方法,即:
You can only do that in .NET 4. Sorry dont know the details.
Edit:
If you are comfortable with Reflection.Emit, you could emit a method calling those expressions in sequence.
Another alternative:
Create a 'do' method, ie:
看待这个问题的另一种方法是记住委托是多播的;您可以多次组合
Action
;Another way to look at this problem is to remember that delegates are multi-cast; you can combine an
Action
many times;