首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用字符串对象成员名处理IQueryable.OrderBy扩展中的无效输入

使用字符串对象成员名处理IQueryable.OrderBy扩展中的无效输入
EN

Stack Overflow用户
提问于 2018-05-13 16:08:19
回答 2查看 48关注 0票数 0

我为IQueryable OrderBy (以及OrderByDescending、ThenBy和ThenByDescending)编写了一个扩展方法,这些方法都调用了函数CreateExpression来获取用于排序的表达式。

问题是,如果有人使用无效的参数调用此方法,例如一个字符串,该字符串不是正在排序的对象类型中的成员名称。这就是我检查pi是否为空的原因。现在,如果参数无效且pi为null,则需要返回除null以外的其他内容,但我不太确定如何做到这一点。我想在不排序的情况下返回一个表达式,这可能吗?我怎么做呢?

代码语言:javascript
复制
    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));
            }
        }

        //todo
        return null;
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-13 16:35:11

潜在的解决方案是使用这样的属性表达式。将属性选择器传递到方法中,而不是字符串:

代码语言:javascript
复制
Expression<Func<T, TProperty>> propertySelector

在您的方法中,您可以获得属性的名称并使用它,就像在代码中一样:

代码语言:javascript
复制
private static string GetPropertyName<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertySelector)
{
    MemberExpression member = propertySelector.Body as MemberExpression;
    PropertyInfo propInfo = member.Member as PropertyInfo;
    return propInfo.Name;
}

您的方法签名如下所示:

代码语言:javascript
复制
public static IQueryable<T> OrderBy<T, TProperty>(this IQueryable<T> source, Expression<Func<T, TProperty>> propertySelector)

你可以这样称呼它:

代码语言:javascript
复制
collection.OrderBy(p => p.UserName)

您将得到静态输入,并可以删除魔术字符串。

否则,我会抛出一个InvalidOperationException,因为这是一个无效的情况,并且您的代码的用户应该被告知异常-而不是代码默默地失败。

票数 1
EN

Stack Overflow用户

发布于 2018-05-13 16:45:39

由于您已经编写了扩展方法来处理任何类型(您没有约束),所以如果用户提供了一个不存在的属性名,那么唯一的选项就是抛出一个异常。你也没什么别的办法。

但是,如果您对T应用了一个简单的约束,那么在所提供的属性不存在的情况下,可以使用它来提供默认的排序。以下是如何:

  1. 创建一个接口并让所有T实现该接口: 公共接口IOrderable { int { get;}
  2. 更改扩展并对其应用约束。然后,如果找不到所提供的属性名称,则返回一个表达式,默认情况下该表达式将在Id列上排序: 私有静态MethodCallExpression CreateExpression(IQueryable源,字符串methodName,字符串orderBy),其中T: IOrderable { //您的代码.//这里是todo //,我们在这里返回一个表达式,该表达式默认为var parameterDef = Expression.Parameter(typeof(T),"p");PropertyInfo piDef =typeof(T).GetProperty(IOrderable.Id);MemberExpression meDef = Expression.MakeMemberAccess(parameterDef,piDef);var orderByExpDef = Expression.Lambda(meDef,parameterDef);返回Expression.Call(typeof(Queryable),methodName,new Type[] { typeof(T),piDef.PropertyType },source.Expression,Expression.Quote(orderByExpDef));}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50318075

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档