0

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

假设我有一个基于人员的查询,并且我希望能够过滤名字和姓氏,并且在这两种情况下我都希望能够使用过滤条件,例如StartsWith, ' EndsWith, Contains, Equals

所以现在我有一个方法:

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.
  }
}

现在,我还希望能够为 LastName 构建相同的过滤器。重新复制和粘贴整个内容似乎很愚蠢和浪费,只需替换p.FirstNamep.LastName. 我还有一堆我想过滤的其他字符串字段,我真的不想为每个字段重写整个方法!

有没有办法抽象这个,也许使用LinqKit,这样我就可以提出一个更通用的方法,具有以下近似签名:

Expression<Func<Person, bool>> GetFilter(Expression<Func<Person, string>> stringExpression, Comparator comparator, string compareValue) {}

这样我就可以在里面FirstNameFilter像这样调用它:

return GetFilter(p => p.FirstName, comparator, compareValue);
4

1 回答 1

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;
    }
}
于 2013-07-05T07:11:28.747 回答