在 C# 中组合两个 lambda 表达式
给定这样的类结构:
public class GrandParent
{
public Parent Parent { get; set;}
}
public class Parent
{
public Child Child { get; set;}
}
public class Child
{
public string Name { get; set;}
}
和以下方法签名:
Expression<Func<TOuter, TInner>> Combine (Expression<Func<TOuter, TMiddle>>> first, Expression<Func<TMiddle, TInner>> second);
我如何实现所述方法,以便我可以像这样调用它:
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
这样输出最终为:
gp => gp.Parent.Child.Name
这可能吗?
每个 Func 的内容永远只是一个 MemberAccess
。我不想让 output
成为嵌套函数调用。
谢谢
Given a class structure like this:
public class GrandParent
{
public Parent Parent { get; set;}
}
public class Parent
{
public Child Child { get; set;}
}
public class Child
{
public string Name { get; set;}
}
and the following method signature:
Expression<Func<TOuter, TInner>> Combine (Expression<Func<TOuter, TMiddle>>> first, Expression<Func<TMiddle, TInner>> second);
How can I implement said method so that I can call it like this:
Expression<Func<GrandParent, Parent>>> myFirst = gp => gp.Parent;
Expression<Func<Parent, string>> mySecond = p => p.Child.Name;
Expression<Func<GrandParent, string>> output = Combine(myFirst, mySecond);
such that output ends up as:
gp => gp.Parent.Child.Name
Is this possible?
The contents of each Func will only ever be a MemberAccess
. I'd rather not end up with output
being a nested function call.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
好的;相当长的片段,但这是表达式重写器的入门;它还不能处理一些情况(我稍后会修复它),但它适用于给定的示例和许多其他示例:
OK; pretty long snippet, but here's a starter for an expression-rewriter; it doesn't handle a few cases yet (I'll fix it later), but it works for the example given and a lot of others:
我假设您的目标是获得如果您实际编译了“组合”lambda,您将获得的表达式树。构造一个新的表达式树要容易得多,只需适当地调用给定的表达式树,但我认为这不是您想要的。
马特·沃伦 (Matt Warren) 的博客可能值得您阅读。他设计并实现了所有这些东西,并撰写了大量有关有效重写表达式树的方法的文章。 (我只做了编译器的事情。)
更新:
如 此相关答案点,在 .NET 4 中,现在有一个表达式重写器的基类,它使此类事情变得更加容易。
I am assuming that your goal is to obtain the expression tree that you would have obtained, had you actually compiled the "combined" lambda. It's much easier to construct a new expression tree that simply invokes the given expression trees appropriately, but I assume that's not what you want.
Matt Warren's blog might be a good thing for you to read. He designed and implemented all this stuff and has written a lot about ways to rewrite expression trees effectively. (I only did the compiler end of things.)
UPDATE:
As this related answer points out, in .NET 4 there is now a base class for expression rewriters that makes this sort of thing a lot easier.
我不确定你所说的不是嵌套函数调用是什么意思,但这可以解决问题 - 举个例子:
我不知道生成的代码与单个 lambda 表达式相比有多高效,但我怀疑不会太糟糕。
I'm not sure what you mean by it not being a nested function call, but this will do the trick - with an example:
I don't know how efficient the generated code will be compared with a single lambda expression, but I suspect it won't be too bad.
要获得完整的解决方案,请查看LINQKit:
output.ToString()< /code> 打印出来
,而 Jon Skeet 的解决方案产生
我猜这就是您所说的“嵌套函数调用”。
For a complete solution have a look at LINQKit:
output.ToString()
prints outwhereas Jon Skeet's solution yields
I guess that's what you're referring to as 'nested function calls'.
试试这个:
和用法:
Try this:
and the usage:
经过半天的挖掘,得出了以下解决方案(比公认的答案简单得多):
对于通用 lambda 组合:
这将两个表达式合并为一个,即将第一个表达式应用于第二个表达式的结果。
因此,如果我们有 f(y) 和 g(x),则 merge(f,g)(x) === f(g(x))
具有传递性和结合性,因此组合器可以链接起来
更具体地说,对于属性访问 ( MVC/EF 所需):
注意:
fProp
必须是一个简单的属性访问表达式,例如x =>; x.Prop
。fObj
可以是任何表达式(但必须与 MVC 兼容)After a half-day's digging came up with the following solution (much simpler than the accepted answer):
For generic lambda composition:
This combines two expressions in one, i.e. applies the first expression to the result of the second.
So if we have f(y) and g(x), combine(f,g)(x) === f(g(x))
Transitive and associative, so the combinator can be chained
More specifically, for property access (needed for MVC/EF):
Note:
fProp
must be a simple property access expression, such asx => x.Prop
.fObj
can be any expression (but must be MVC-compatible)借助名为 Layer Over LINQ 的工具包,有一种扩展方法可以准确执行此操作,它将两个表达式组合起来创建一个新表达式适合在 LINQ to Entities 中使用。
With a toolkit called Layer Over LINQ, there's an extension method that does exactly this, combines two expressions to create a new one suitable for use in LINQ to Entities.