2017-02-05 1 views
3

У меня есть класс репозитория, который позволяет для запросов с использованием лямбда-выражения (упрощенный частичный код):Изменение выражения предиката для класса оберточной

public class SomeRepository<T>: IRepository<T> 
{ 
    public IList<T> Find(Expression<Func<T, bool>> filter) 
    { 
     return SomeQueryProvider.Where(filter).ToList(); 
    } 
}  

Однако для конкретного поставщика У меня есть необходимость, чтобы обернуть исходный объект в другом классе:

public class Wrapped<T> 
{ 
    public T OriginalObject { get; set; } 
} 

Таким образом, в данном случае, мне также нужно обернуть выражение входящий предиката в другое выражение:

public class AnotherRepository<T>: IRepository<T> 
{ 
    public IList<T> Find(Expression<Func<T, bool>> filter) 
    { 
     Expression<Func<Wrapped<T>, bool>> wrappedFilter = ... 
     return AnotherQueryProvider.Where(wrappedFilter).ToList(); 
    } 
} 

Например, x => x.ParentId == 123 должно стать x => x.OriginalObject.ParentId == 123.

Я не могу найти примеры для этого сценария, и мне с этим трудно справиться. Как я могу добавить предикатное выражение с свойством OriginalObject?

+2

насчет выбора 'OriginalObject', а затем используйте 'filter', как есть:' AnotherQueryProvider.Select (x => x.OriginalObjext) .Where (filter) .ToList(); ' –

+0

На самом деле есть много примеров, если вы ищете [составление выражений] (http: //stackoverflow.com/search?q=c ompose +), но, как заметил другой комментатор, вы можете просто обменять 'Where' и' Select' (ваш образец должен иметь 'Select' для компиляции). –

+0

@OfirWinegarten спасибо, по какой-то причине я не думал о самом простом решении. – Carvellis

ответ

4

Ответ на конкретный вопрос.

Учитывая выражение

Expression<Func<Wrapped<T>, T>> e1 = w => w.OriginalObject; 

преобразования выражение

Expression<Func<T, bool>> e2 = o => o.ParentId == 123; 

к

Expression<Func<Wrapped<T>, T>> e3 = w => w.OriginalObject.ParentId == 123; 

является вопросом замены вхождения параметра o внутри e2 тела с w.OriginalObject (тело e1). Что-то вроде string replace, но для выражений :)

Сначала вам нужен метод, который заменяет параметр выражения чем-то другим. Вот тот, который я использую:

public static partial class ExpressionUtils 
{ 
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target) 
    { 
     return new ParameterReplacer { Source = source, Target = target }.Visit(expression); 
    } 
    class ParameterReplacer : ExpressionVisitor 
    { 
     public ParameterExpression Source; 
     public Expression Target; 
     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      return node == Source ? Target : base.VisitParameter(node); 
     } 
    } 
} 

Теперь рассмотренный метод может выглядеть так:

partial class ExpressionUtils 
{ 
    public static Expression<Func<Wrapped<T>, TResult>> ToWrapped<T, TResult>(this Expression<Func<T, TResult>> source) 
    { 
     Expression<Func<Wrapped<T>, T>> unwrap = w => w.OriginalObject; 
     var parameter = unwrap.Parameters[0]; 
     var body = source.Body.ReplaceParameter(source.Parameters[0], unwrap.Body); 
     return Expression.Lambda<Func<Wrapped<T>, TResult>>(body, parameter); 
    } 
} 

и использование

var wrappedFilter = filter.ToWrapped(); 
+0

Я приму этот ответ, потому что он отвечает на вопрос, хотя решение, данное в комментариях к вопросу, лучше подходит в этом случае. – Carvellis

Смежные вопросы