Поскольку вы хотите, чтобы ваше выражение селектора свойств выполняло соответствующие вызовы динамически, вы должны создать для него новое выражение.Вы не можете использовать предоставленный селектор как есть, так как он в настоящее время набран Expression<Func<T, object>>
и не возвращает ваш конкретный тип Expression<Func<T, SomeType>>
.Вы можете получить его для компиляции, изменив аргументы типа вызова на accept object
, но он не будет работать должным образом, так как он будет выполнять сравнения ссылок на объекты (и ваш поставщик LINQ может отклонить его в любом случае).
Чтобы воссоздать выражение селектора, вы можете сделать следующее:
private static IQueryable<T> BuildQuery<T>(
IQueryable<T> query,
string methodName,
Expression<Func<T, object>> property)
{
var typeArgs = new[] { query.ElementType, property.Body.Type };
var delegateType = typeof(Func<,>).MakeGenericType(typeArgs);
var typedProperty = Expression.Lambda(delegateType, property.Body, property.Parameters);
var methodCall = Expression.Call(
typeof(Queryable),
methodName,
typeArgs,
query.Expression,
typedProperty);
return query.Provider.CreateQuery<T>(methodCall);
}
Хорошей альтернативой этому было бы сделать тип свойства также универсальным.Таким образом, с самого начала вы получите строго типизированный селектор.
private static IQueryable<TSource> BuildQuery<TSource, TProperty>(
IQueryable<TSource> query,
string methodName,
Expression<Func<TSource, TProperty>> property)
{
var typeArguments = property.Type.GetGenericArguments();
var methodCall = Expression.Call(
typeof(Queryable),
methodName,
typeArguments,
query.Expression,
property);
return query.Provider.CreateQuery<TSource>(methodCall);
}