【发布时间】:2012-02-01 08:39:13
【问题描述】:
问题来了:
我们使用表格对象来允许用户执行一些功能,如搜索、排序、分页等。这些表格效果很好。但是其中一项功能存在问题: 排序 (=OrderBy)。
事实上,为了允许排序,我们在每一列中设置了一个表示表达式的字符串: 例如,如果表达式是Person => Person.Id,那么字符串就是Id; 如果表达式是 Person => Person.Address.Street,则字符串是 Address.Street。
在第一种情况下(Person => Person.Id),它工作得很好,因为它不是子对象。 但在第二种情况下(Person => Person.Address.Street),它不会,因为 Address 对象可能为空。
为了允许从字符串执行 Orderby,我在另一篇文章中发现了以下方法:
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
private static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<T>)result;
}
你们有没有一个想法可以让我添加一个不会选择带有 subobject == null 的对象的条件?或者阻止它尝试从一个为空的对象访问属性?
编辑:
检查类似于:list.OrderBy(x => (x.Address != null) ? x.Address.Street : string.Empty)。
所以我需要在 x 和 final 字段之间的每个对象上添加一个空检查。 是否可以使用这些方法来做到这一点?
编辑 2:
我已经尝试替换
Expression.Property(expr, pi);
通过
expr = Expression.Condition(
Expression.Equal(expr, Expression.Constant(null)),
Expression.Constant(String.Empty),
Expression.Property(expr, pi));
但它似乎不起作用。我得到以下异常:
Argument types do not match
知道我应该如何知道 expr 访问的字段的默认值吗?
【问题讨论】:
-
能否在调用 OrderBy 方法之前检查属性是否为
null? -
那是我不想做的。我宁愿在表达式中包含另一部分来检查我,这样我就不必将代码分成多个部分。但我不知道如何包含此检查。
标签: c# generics sql-order-by expression expression-trees