1、使用特性标记属性

2、将filter转换为expression

/// <summary>
    /// 运算
    /// </summary>
    public class Operater
    {
        /// <summary>
        /// 等于
        /// </summary>
        public const string Equal = "eq";
        /// <summary>
        /// 不等于
        /// </summary>
        public const string NotEqual = "ne";
        /// <summary>
        /// 大于
        /// </summary>
        public const string GreaterThan = "gt";
        /// <summary>
        /// 大于等于
        /// </summary>
        public const string GreaterThanOrEqual = "gte";
        /// <summary>
        /// 小于
        /// </summary>
        public const string LessThan = "lt";
        /// <summary>
        /// 小于等于
        /// </summary>
        public const string LessThanOrEqual = "lte";
        /// <summary>
        /// 包含
        /// </summary>
        public const string Contains = "cn";
        /// <summary>
        /// 不包含
        /// </summary>
        public const string NotContains = "nc";
        /// <summary>
        /// 包含
        /// </summary>
        public const string In = "in";
        /// <summary>
        /// 以XX开头
        /// </summary>
        public const string StartsWith = "sw";
        public const string StringGreaterThanOrEqual = "sgte";
        public const string StringLessThanOrEqual = "slte";
    }
public interface IFilter
    {
        /// <summary>
        /// 排序字段
        /// </summary>
        string sidx { get; set; }

        /// <summary>
        /// 类型 asc/desc
        /// </summary>
        string sord { get; set; }

        /// <summary>
        /// 当前页码
        /// </summary>
        int page { get; set; }

        /// <summary>
        /// 每页显示的数据量
        /// </summary>
        int rows { get; set; }
    }
public abstract class QueryFilter : IFilter
    {
        public QueryFilter()
        {
            sidx = "Id";
            this.sord = "desc";
            this.page = 1;
            this.rows = 10;
        }
        public QueryFilter(string sidx,string sord,int page,int rows)
        {
            this.sidx = sidx;
            this.sord = sord;
            this.page = page;
            this.rows = rows;
        }

        /// <summary>
        /// 排序字段
        /// </summary>
        public string sidx { get; set; }
        /// <summary>
        /// 类型 asc/desc
        /// </summary>
        public string sord { get; set; }
        /// <summary>
        /// 当前页码
        /// </summary>
        public int page { get; set; }
        /// <summary>
        /// 每页显示的数据量
        /// </summary>
        public int rows { get; set; }
    }
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class FieldFilterAttribute : Attribute
    {
        public string FieldName { get; set; }
        public string Operater { get; set; }

        public FieldFilterAttribute(string operater)
        {
            this.Operater = operater;
        }

        public FieldFilterAttribute(string fieldName, string operater)
        {
            this.FieldName = fieldName;
            this.Operater = operater;
        }
    }
public static class MemberInfoExtension
    {
        public static bool HasCustomAttribute<T>(this MemberInfo prop) where T : Attribute
        {
            return prop.GetCustomAttribute<T>() != null;
        }
    }
public static class StringExtension
    {
        /// <summary>
        /// 判断字符串是否为空或null
        /// </summary>
        public static bool IsEmpty(this string value)
        {
            return ((value == null) || (value.Length == 0));
        }

        /// <summary>
        /// 判断字符串是否不为空
        /// </summary>
        public static bool IsNotEmpty(this string value)
        {
            return !value.IsEmpty();
        }
}
public static class ModelFilterExtention
    {
        /// <summary>
        /// 转换为表达式
        /// </summary>
        /// <typeparam name="TModel">过滤实体</typeparam>
        /// <param name="filter">过滤对象</param>
        /// <param name="alias">别名</param>
        /// <returns></returns>
        public static Expression<Func<TModel, bool>> ToExpression<TModel>(this IFilter filter, string alias = "x")
            where TModel : class
        {
            var parameter = Expression.Parameter(typeof(TModel), alias);
            var expressions = filter.ToExpressions<TModel>(parameter);

            Expression expression = null;
            foreach (var exp in expressions)
            {
                if (expression == null)
                {
                    expression = exp;
                }
                else
                {
                    expression = Expression.And(expression, exp);
                }
            }

            if (expression == null)
            {
                return null;
            }
            else
            {
                return Expression.Lambda<Func<TModel, bool>>(expression, parameter);
            }
        }

        public static IEnumerable<Expression> ToExpressions<TModel>(this IFilter filter, ParameterExpression parameter)
            where TModel : class
        {
            var modelType = typeof(TModel);

            var properties = filter.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                .Where(x => x.HasCustomAttribute<FieldFilterAttribute>());

            foreach (var property in properties)
            {
                var attribute = property.GetCustomAttribute<FieldFilterAttribute>();
                if (attribute == null)
                {
                    continue;
                }

                var fieldName = property.Name;
                if (attribute.FieldName.IsNotEmpty())
                {
                    fieldName = attribute.FieldName;
                }

                var fieldValue = property.GetValue(filter);

                if (fieldName.IsEmpty() || fieldValue.Equals("null"))
                {
                    continue;
                }

                var member = Expression.Property(parameter, modelType.GetProperty(fieldName));
                var operater = property.GetCustomAttribute<FieldFilterAttribute>().Operater;

                Expression expression;

                switch (operater)
                {
                    case Operater.GreaterThanOrEqual:
                        expression = Expression.GreaterThanOrEqual(member, Expression.Constant(fieldValue, member.Type));
                        break;
                    case Operater.LessThan:
                        expression = Expression.LessThan(member, Expression.Constant(fieldValue, member.Type));
                        break;
                    case Operater.LessThanOrEqual:
                        expression = Expression.LessThanOrEqual(member, Expression.Constant(fieldValue, member.Type));
                        break;
                    case Operater.GreaterThan:
                        expression = Expression.GreaterThan(member, Expression.Constant(fieldValue, member.Type));
                        break;
                    case Operater.Contains:
                        expression = Expression.Call(member, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(fieldValue, typeof(string)));
                        break;
                    case Operater.NotContains:
                        expression = Expression.Not(Expression.Call(member, typeof(string).GetMethod("Contains"), Expression.Constant(fieldValue, typeof(string))));
                        break;
                    case Operater.In:
                        var fieldValueList = Expression.Constant(fieldValue.ToString().Split(',').ToList(), typeof(List<string>));
                        expression = Expression.Call(fieldValueList, typeof(List<string>).GetMethod("Contains"), member);
                        break;
                    case Operater.StartsWith:
                        expression = Expression.Call(member, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), Expression.Constant(fieldValue, typeof(string)));
                        break;
                    case Operater.StringGreaterThanOrEqual:
                        expression = Expression.GreaterThanOrEqual(
                            Expression.Call(member, typeof(String).GetMethod("CompareTo", new Type[] { typeof(String) }), Expression.Constant(fieldValue, typeof(string))),
                            Expression.Constant(0, typeof(Int32)));
                        break;
                    case Operater.StringLessThanOrEqual:
                        expression = Expression.LessThanOrEqual(
                            Expression.Call(member, typeof(String).GetMethod("CompareTo", new Type[] { typeof(String) }), Expression.Constant(fieldValue, typeof(string))),
                            Expression.Constant(0, typeof(Int32)));
                        break;
                    case Operater.NotEqual:
                        expression = Expression.NotEqual(member, Expression.Constant(fieldValue, member.Type));
                        break;
                    case Operater.Equal:
                    default:
                        expression = Expression.Equal(member, Expression.Constant(fieldValue, member.Type));
                        break;
                }

                yield return expression;
            }
        }

        /// <summary>
        /// 获取表达式()
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="field"></param>
        /// <param name="alias"></param>
        /// <returns></returns>
        public static Expression<Func<Type, object>> GetExpression<Type>(string field, string alias)
        {
            var parameterExpression = Expression.Parameter(typeof(Type), alias);
            var memberExpression = Expression.Property(parameterExpression, typeof(Type).GetProperty(field));
            Expression conversion = Expression.Convert(memberExpression, typeof(object));
            return Expression.Lambda<Func<Type, dynamic>>(conversion, parameterExpression);
        }
    }
/// <summary>
    /// 用户查询
    /// </summary>
    public class MemberViewFilter : QueryFilter
    {

        [Display(Name = "用户名")]
        [FieldFilter(Operater.Equal)]
        public string UserName { get; set; }
        [Display(Name = "手机号码")]
        [FieldFilter(Operater.Equal)]
        public string Password { get; set; }
    }
[HttpPost]
        public IActionResult Query(MemberViewFilter filter)
        {

            var expression = filter.ToExpression<Member>();
            List<Member> list;
            using (EFDbContext db = new EFDbContext())
            {
                list = db.Set<Member>().Where(expression).ToList();
            }
            return Json(list);
        }