我正在寻求一种方法来合并两个lambda表达式,而不使用
我唯一想到的做法是使用 ExpressionVisitor,就像这样:
Expression.Invoke
。我想要构建一个新的表达式,将两个单独的表达式串起来。请考虑下面的代码: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 helpers一起使用。我有一些深层嵌套的ViewModels和一些HtmlHelper扩展,帮助处理它们,因此表达式仅需要成为内置MVC helpers的MemberExpressions
集合,才能正确处理它们并构建正确的深度嵌套名称属性值。我的第一反应是使用Expression.Invoke()
调用第一个表达式,然后将其链接到第二个表达式,但MVC helpers并不太喜欢它。它失去了它的分层上下文。