我正在尋找一種方式兩個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