You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于字符串成员名扩展IQueryable.OrderBy时的无效输入处理

当然可行!其实思路很简单——当参数无效时,我们只需要返回一个不改变原序列顺序的排序表达式就行,本质上就是让排序操作变成一个“空操作”。而且必须这么做,否则后续如果链式调用ThenBy这类方法会直接报错(因为ThenBy仅支持IOrderedQueryable类型)。

具体实现思路

当检测到无效参数(比如传入的属性名不存在,导致pi为null)时,我们构造一个所有元素返回相同值的键选择器表达式。因为当所有元素的排序键完全相同时,排序算法会保留原序列的顺序(稳定排序特性),这样就等价于“没有执行排序”。同时,这个表达式会生成合法的IOrderedQueryable,确保后续链式调用不受影响。

修改后的完整代码

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string orderBy) {
    if (!string.IsNullOrWhiteSpace(orderBy)) {
        var resultExp = CreateExpression(source, "OrderBy", orderBy);
        return source.Provider.CreateQuery<T>(resultExp);
    } else {
        return source;
    }
}

private static MethodCallExpression CreateExpression<T>(IQueryable<T> source, string methodName, string orderBy) {
    if (methodName != "OrderBy" && methodName != "OrderByDescending" && methodName != "ThenBy" && methodName != "ThenByDescending")
        methodName = "OrderBy";

    if (!string.IsNullOrWhiteSpace(orderBy)) {
        PropertyInfo pi = typeof(T).GetProperty(orderBy);
        if (pi != null) {
            var parameter = Expression.Parameter(typeof(T), "p");
            MemberExpression me = Expression.MakeMemberAccess(parameter, pi);
            var orderByExp = Expression.Lambda(me, parameter);
            return Expression.Call(typeof(Queryable), methodName, new Type[] { typeof(T), pi.PropertyType }, source.Expression, Expression.Quote(orderByExp));
        }
    }

    // 参数无效时,构造不改变原顺序的排序表达式
    var parameter = Expression.Parameter(typeof(T), "p");
    // 用object类型的null作为统一排序键,兼容所有类型
    var keySelector = Expression.Lambda<Func<T, object>>(
        Expression.Constant(null, typeof(object)),
        parameter
    );

    return Expression.Call(
        typeof(Queryable),
        methodName,
        new Type[] { typeof(T), typeof(object) },
        source.Expression,
        Expression.Quote(keySelector)
    );
}

额外说明

  • 如果你担心值类型的空引用问题,可以把键选择器改成返回T的默认值并转换为object:
    var keySelector = Expression.Lambda<Func<T, object>>(
        Expression.Convert(Expression.Default(typeof(T)), typeof(object)),
        parameter
    );
    
  • 这个方案同时兼容OrderByDescending、ThenBy、ThenByDescending所有方法,因为不管是升序还是降序,当所有键相同时,顺序都不会改变。

内容的提问来源于stack exchange,提问作者crazysnake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:28:55