用可变比较器复合表达?

时间:2013-07-04 17:57:12

标签: c# linq entity-framework-5 expression-trees linqkit

我正在编写一个查询框架,并尽量使其尽可能通用。

假设我有一个基于人的查询,我希望能够对名字和姓氏进行过滤,在这两种情况下我都希望能够使用过滤条件,例如StartsWith,'{ {1}},EndsWithContains

所以现在我有一个方法:

Equals

现在,我还希望能够为LastName构建相同的过滤器。将整个事情重新复制并粘贴,只是将private Expression<Func<Person, bool>> FirstNameFilter(Comparator comparator, string compareValue) { switch (comparator) { case Comparator.Equal: return p => p.FirstName == compareValue; case Comparator.Contains: return p => p.FirstName.Contains(compareValue); case Comparator.StartsWith: return p => p.FirstName.StartsWith(compareValue); // etc. } } 替换为p.FirstName,这似乎是愚蠢而浪费的。我还有一些我想要过滤的其他字符串字段,我真的不想为每一个重写这整个方法!

是否有某种方法可以抽象出来,也许使用LinqKit,这样我就可以使用以下近似签名来提供更通用的方法:

p.LastName

这样我就可以在Expression<Func<Person, bool>> GetFilter(Expression<Func<Person, string>> stringExpression, Comparator comparator, string compareValue) {} 内调用它:

FirstNameFilter

1 个答案:

答案 0 :(得分:3)

类似的东西(未经测试,但你有想法)应该可以帮助你构建所需的表达式:

public static class LinqQueries
{
    private static MethodInfo toLowerMethod = typeof(String).GetMethod("ToLower", Type.EmptyTypes);
    private static MethodInfo startsWithMethod= typeof(String).GetMethod("StartsWith", new Type[] { typeof(String) });
    private static MethodInfo containsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
    private static MethodInfo endsWithMethod= typeof(String).GetMethod("EndsWith", new Type[] { typeof(String) });

    public static Expression<Func<T, bool>> GetFilter(Expression<Func<T, string>> expression, Comparator comparator, string compareValue) {
        ParameterExpression parameterExpression = null;
        var memberExpression = GetMemberExpression(expression.Body, out parameterExpression);
        Expression constExp = Expression.Constant(compareValue);
        switch (comparator) {

        case Comparator.Contains:
          memberExpression = Expression.Call(memberExpression, containsMethod,constExp);
        break;
        case Comparator.StartsWith:
          memberExpression = Expression.Call(memberExpression, startsWithMethod, constExp);
        break;
        //etc.
        default :
          memberExpression = Expression.Equal(memberExpression, constExp);
        break;
      }

      return Expression.Lambda<Func<T, bool>>(memberExpression, new[]{parameterExpression});
  }


  private static Expression GetMemberExpression(Expression expression, out ParameterExpression parameterExpression)
    {
        parameterExpression = null;
        if (expression is MemberExpression)
        {
            var memberExpression = expression as MemberExpression;
            while (!(memberExpression.Expression is ParameterExpression))
                memberExpression = memberExpression.Expression as MemberExpression;
            parameterExpression = memberExpression.Expression as ParameterExpression;
            return expression as MemberExpression;
        }
        if (expression is MethodCallExpression)
        {
            var methodCallExpression = expression as MethodCallExpression;
            parameterExpression = methodCallExpression.Object as ParameterExpression;
            return methodCallExpression;
        }
        return null;
    }
}