Я ищу способ объединения двух лямбда-выражений без использования 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);
Работает, ноэто кажется мне немного неуклюжим.Я все еще пытаюсь обернуть голову выражениями и задаюсь вопросом, есть ли более идиоматический способ выразить это, и у меня есть подлое подозрение, что я упустил что-то очевидное.1021 * Я хочу сделать это, чтобы использовать его с помощниками ASP.net MVC 3 Html.У меня есть несколько глубоко вложенных ViewModels и несколько расширений HtmlHelper, которые помогают справиться с ними, поэтому выражение должно быть просто набором MemberExpressions
, чтобы встроенные помощники MVC могли правильно их обработать и построить правильно глубоко вложенные значения атрибута имени.Моим первым инстинктом было использовать Expression.Invoke()
, вызывать первое выражение и связывать его со вторым, но помощникам MVC это не очень понравилось.Он потерял свой иерархический контекст.