修改谓词表达式以换行 class
Modifying predicate expression for wrapping class
我有一个存储库 class,它允许使用 lambda 表达式(简化的部分代码)进行查询:
public class SomeRepository<T>: IRepository<T>
{
public IList<T> Find(Expression<Func<T, bool>> filter)
{
return SomeQueryProvider.Where(filter).ToList();
}
}
但是,对于特定的提供者,我需要将原始对象包装在另一个 class:
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
属性?
回答具体问题。
给定表达式
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;
是将 e2
主体中出现的 o
参数替换为 w.OriginalObject
(e1
的主体)。类似于字符串替换,但用于表达式 :)
首先你需要一个用其他东西替换表达式参数的方法。这是我使用的那个:
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();
我有一个存储库 class,它允许使用 lambda 表达式(简化的部分代码)进行查询:
public class SomeRepository<T>: IRepository<T>
{
public IList<T> Find(Expression<Func<T, bool>> filter)
{
return SomeQueryProvider.Where(filter).ToList();
}
}
但是,对于特定的提供者,我需要将原始对象包装在另一个 class:
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
属性?
回答具体问题。
给定表达式
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;
是将 e2
主体中出现的 o
参数替换为 w.OriginalObject
(e1
的主体)。类似于字符串替换,但用于表达式 :)
首先你需要一个用其他东西替换表达式参数的方法。这是我使用的那个:
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();