如何修改自定义OrderBy Lambda表达式,实现按集合属性Count()排序?
修改OrderBy Lambda表达式方法以支持集合属性按Count()排序
现有方法可生成针对普通属性的OrderBy表达式,但需扩展逻辑,当排序属性为集合类型时,自动调用Count()方法生成排序表达式。同时修正原代码中冗余且错误的属性获取逻辑。
修改后的完整代码
public IOrderedQueryable<T> createLambdaOrderBy<T>(IQueryable<T> source, PropertyInfo orderByProperty, bool desc = false) { string command = desc ? "OrderByDescending" : "OrderBy"; var type = typeof(T); var property = orderByProperty; // 直接使用传入的PropertyInfo参数 ParameterExpression parameter = Expression.Parameter(type, "p"); MemberExpression propertyAccess = Expression.MakeMemberAccess(parameter, property); // 判断属性是否为集合类型(实现IEnumerable),排除string类型 var propertyType = property.PropertyType; if (typeof(System.Collections.IEnumerable).IsAssignableFrom(propertyType) && propertyType != typeof(string)) { // 根据集合类型获取对应的Count()扩展方法 MethodInfo countMethod; if (propertyType.IsGenericType) { // 泛型集合:获取带泛型参数的Count方法 countMethod = typeof(Enumerable).GetMethods() .First(m => m.Name == "Count" && m.GetParameters().Length == 1) .MakeGenericMethod(propertyType.GetGenericArguments()[0]); } else { // 非泛型集合:获取针对IEnumerable的Count方法 countMethod = typeof(Enumerable).GetMethod("Count", new[] { typeof(System.Collections.IEnumerable) }); } // 构建调用Count()的表达式节点 propertyAccess = Expression.Call(countMethod, propertyAccess); } LambdaExpression orderByExpression = Expression.Lambda(propertyAccess, parameter); // 调整泛型参数:将排序结果类型改为Count()返回的int类型 var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, propertyAccess.Type }, source.Expression, Expression.Quote(orderByExpression)); return (IOrderedQueryable<T>)source.Provider.CreateQuery<T>(resultExpression); }
关键改动说明
- 集合类型识别:检查属性是否实现
IEnumerable接口,同时排除string类型(避免将字符串误判为集合)。 - Count()方法适配:针对泛型和非泛型集合分别获取对应的
Count扩展方法,保证兼容不同类型的集合。 - 表达式重构:若为集合属性,在原属性访问表达式基础上,构建调用
Count()的表达式节点,替换原直接属性访问逻辑。 - 类型参数修正:创建OrderBy表达式时,将排序结果类型改为
Count()返回的int类型,确保表达式类型匹配。
修改后,当传入集合类型的排序属性时,生成的表达式将变为:
.OrderBy(p => p.SomeProperty.Count())
普通属性则保持原有排序逻辑不变。
内容的提问来源于stack exchange,提问作者patsy2k
相关产品推荐
相关产品推荐

