我为IQueryable OrderBy (以及OrderByDescending、ThenBy和ThenByDescending)编写了一个扩展方法,这些方法都调用了函数CreateExpression来获取用于排序的表达式。
问题是,如果有人使用无效的参数调用此方法,例如一个字符串,该字符串不是正在排序的对象类型中的成员名称。这就是我检查pi是否为空的原因。现在,如果参数无效且pi为null,则需要返回除null以外的其他内容,但我不太确定如何做到这一点。我想在不排序的情况下返回一个表达式,这可能吗?我怎么做呢?
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;
}发布于 2018-05-13 16:35:11
潜在的解决方案是使用这样的属性表达式。将属性选择器传递到方法中,而不是字符串:
Expression<Func<T, TProperty>> propertySelector在您的方法中,您可以获得属性的名称并使用它,就像在代码中一样:
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;
}您的方法签名如下所示:
public static IQueryable<T> OrderBy<T, TProperty>(this IQueryable<T> source, Expression<Func<T, TProperty>> propertySelector)你可以这样称呼它:
collection.OrderBy(p => p.UserName)您将得到静态输入,并可以删除魔术字符串。
否则,我会抛出一个InvalidOperationException,因为这是一个无效的情况,并且您的代码的用户应该被告知异常-而不是代码默默地失败。
发布于 2018-05-13 16:45:39
由于您已经编写了扩展方法来处理任何类型(您没有约束),所以如果用户提供了一个不存在的属性名,那么唯一的选项就是抛出一个异常。你也没什么别的办法。
但是,如果您对T应用了一个简单的约束,那么在所提供的属性不存在的情况下,可以使用它来提供默认的排序。以下是如何:
T实现该接口:
公共接口IOrderable { int { get;}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));}https://stackoverflow.com/questions/50318075
复制相似问题