Jus*_*tin 0 c# linq reflection
我试图动态地使用反射做一个OrderBy
是否给定的sortColumn
(串)为空或不是,一ThenBy
对sortColumn
价值和ThenBy
对硬编码列。像这样:
if (!String.IsNullOrEmpty(sortColumn)) {
var descending = sortDirection == "desc";
views = views.AsQueryable()
.OrderByNull<ToDoView>(sortColumn, true) // extension method
.OrderBy<ToDoView>(sortColumn, descending, true) // extension method
.ThenBy(v => v.summary ?? v.description).ToList();
}
Run Code Online (Sandbox Code Playgroud)
使用其他 SO 答案,我能够使OrderBy
扩展方法起作用:
public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source,
string orderByProperty, bool desc, bool thenBy = false) {
string command = desc ? "OrderByDescending" : "OrderBy";
if (thenBy)
command = desc ? "ThenByDescending" : "ThenBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(
typeof(Queryable),
command,
new Type[] { type, property.PropertyType },
source.Expression,
Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
Run Code Online (Sandbox Code Playgroud)
这是我的OrderByNull
扩展方法:
public static IOrderedQueryable<TEntity> OrderByNull<TEntity>(this IQueryable<TEntity> source,
string orderByProperty, bool desc, bool thenBy = false) {
string command = desc ? "OrderByDescending" : "OrderBy";
if (thenBy)
command = desc ? "ThenByDescending" : "ThenBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var target = Expression.Constant(null, type);
var equalsMethod = Expression.Call(Expression.Property(parameter, orderByProperty), "Equals", null, target);
var orderByExpression = Expression.Lambda(equalsMethod, parameter);
var resultExpression = Expression.Call(
typeof(Queryable),
command,
new Type[] { type, property.PropertyType },
source.Expression,
Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
Run Code Online (Sandbox Code Playgroud)
执行此扩展方法时,orderByExpression
计算结果为:
{p => p.listName.Equals(null)}
Run Code Online (Sandbox Code Playgroud)
但是,当尝试设置 时resultExpression
,它会引发异常:
System.InvalidOperationException
: '没有泛型方法'OrderByDescending
'在类型'System.Linq.Queryable
'上与提供的类型参数和参数兼容。如果方法是非通用的,则不应提供类型参数。
我不太确定如何解决这个问题,因为这个表达式对我来说是正确的。有任何想法吗?
这是我的最终OrderByNull
扩展方法,在从接受的答案中修复并NullReferenceException
使用 equals 逻辑解决 a 之后:
public static IOrderedQueryable<TEntity> OrderByNull<TEntity>(this IQueryable<TEntity> source,
string orderByProperty, bool desc, bool thenBy = false) {
string command = desc ? "OrderByDescending" : "OrderBy";
if (thenBy)
command = desc ? "ThenByDescending" : "ThenBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var target = Expression.Constant(null, type);
var equalsMethod = Expression.Equal(Expression.Property(parameter, orderByProperty), Expression.Constant(null, typeof(object)));
var orderByExpression = Expression.Lambda(equalsMethod, parameter);
var resultExpression = Expression.Call(
typeof(Queryable),
command,
new Type[] { type, typeof(bool) },
source.Expression,
Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
Run Code Online (Sandbox Code Playgroud)
在失败的情况下,您将property.PropertyType
( new Type[] { type, property.PropertyType }
)指定TKey
为被调用的泛型方法的泛型类型参数OrderBy<TSource, TKey>
,但选择器 lambda 结果类型(应与 匹配TKey
)是bool
,因此例外。
要修复它,请更改
new Type[] { type, property.PropertyType }
Run Code Online (Sandbox Code Playgroud)
到
new Type[] { type, typeof(bool) }
Run Code Online (Sandbox Code Playgroud)
或更一般地(可以在两种方法中使用)
new Type[] { type, orderByExpression.ReturnType }
Run Code Online (Sandbox Code Playgroud)