我正在寻找一种方式两个lambda表达式结合起来,没有在任的表达使用Expression.Invoke
。我想基本上建立一个链接两个单独的表达式的新表达式。请看下面的代码:结合Lambda表达式
class Model {
public SubModel SubModel { get; set;}
}
class SubModel {
public Foo Foo { get; set; }
}
class Foo {
public Bar Bar { get; set; }
}
class Bar {
public string Value { get; set; }
}
而且可以说,我有两个表达式:
Expression<Func<Model, Foo>> expression1 = m => m.SubModel.Foo;
Expression<Func<Foo, string>> expression2 = f => f.Bar.Value;
而且我想加入他们一起在功能上得到下面的表达式:
Expression<Func<Model, string>> joinedExpression = m => m.SubModel.Foo.Bar.Value;
唯一这样我可以认为这样做是为了使用这样的ExpressionVisitor:
public class ExpressionExtender<TModel, TIntermediate> : ExpressionVisitor
{
private readonly Expression<Func<TModel, TIntermediate>> _baseExpression;
public ExpressionExtender(Expression<Func<TModel, TIntermediate>> baseExpression)
{
_baseExpression = baseExpression;
}
protected override Expression VisitMember(MemberExpression node)
{
_memberNodes.Push(node.Member.Name);
return base.VisitMember(node);
}
private Stack<string> _memberNodes;
public Expression<Func<TModel, T>> Extend<T>(Expression<Func<TIntermediate, T>> extend)
{
_memberNodes = new Stack<string>();
base.Visit(extend);
var propertyExpression = _memberNodes.Aggregate(_baseExpression.Body, Expression.Property);
return Expression.Lambda<Func<TModel, T>>(propertyExpression, _baseExpression.Parameters);
}
}
然后将其像这样使用:
var expExt = new ExpressionExtender<Model, Foo>(expression1);
var joinedExpression = expExt.Extend(expression2);
它的工作原理,但感觉有点笨重给我。我仍然试图包裹头部表情,并想知道是否有更通俗的方式来表达这一点,而且我有一种偷偷摸摸的怀疑,我错过了一些明显的东西。
的原因我想这样做是为了与ASP.net MVC 3 HTML辅助使用它。我有一些深层嵌套的ViewModels和一些HtmlHelper扩展来帮助处理这些扩展,所以表达式只需要一个MemberExpressions
的集合,用于内置的MVC帮助程序正确处理它们并构建正确深层嵌套的名称属性值。我的第一本能是使用Expression.Invoke()
,并调用第一个表达式并将其链接到第二个表达式,但MVC帮助者并不那么喜欢。它失去了它的分层上下文。
+1这使我很明白现在看到它。有一件事我没有在原始问题中提及:有没有办法做到这一点,而不会改变开始表达式。例如,我有一个核心表达式,我需要以几种不同的方式进行扩展,每次调用都会生成新的表达式。 – 2012-02-03 18:00:51
@ 32bitkid是的!表达是不可改变的;我没有突变他们中的任何一个! – 2012-02-03 18:14:23
再次感谢您的帮助。 – 2012-02-03 18:21:39