This questions stems from another closed one I posted Here
我有以下电话
var query = _context.Listings.AsQueryable();
query = query.WhereEqualIfSpecified(x => x.HasBalcony, true);
query = query.ApplyRangeFilter(x => x.BedroomsAvailable, 1, 9);
query = query.ApplyRangeFilter(x => x.Baths, 1.0, 2.5);
query = query.ApplyRangeFilter(x => x.Price, 1000.00, 2000.00);
var listings = query.ToList();
I would like to make WhereEqualIfSpecified
generic so its not only for bools but once I change the method to following
public static IQueryable<T> WhereEqualIfSpecified<T>(this IQueryable<T> query, Expression<Func<T, T>> fieldExpression, T filterValue)
{
return filterValue is null
? query
: query.Where(fieldExpression.Compose(value => value.Equals(filterValue)));
}
The call query = query.WhereEqualIfSpecified(x => x.HasBalcony, true);
results in compiler error
方法的类型参数 'ExtensionMethods.WhereEqualIfSpecified(IQueryable, 无法从用法中推断出Expression>,T)'。尝试 明确指定类型参数
public partial class Listing
{
public decimal? Price { get; set; }
public int? BedroomsAvailable { get; set; }
public double? Baths { get; set; }
public bool? HasBalcony { get; set; }
public bool? HasElevator { get; set; }
}
public static class ExtensionMethods
{
public static IQueryable<T> WhereEqualIfSpecified<T>(this IQueryable<T> query, Expression<Func<T, bool?>> fieldExpression, bool? filterValue)
{
return filterValue is null
? query
: query.Where(fieldExpression.Compose(value => value.Equals(filterValue)));
}
public static IQueryable<T> ApplyRangeFilter<T>(this IQueryable<T> query, Expression<Func<T, int?>> filter, int? minValue, int? maxValue)
{
if (minValue is null && maxValue is null) return query;
if (maxValue != null && minValue != null)
{
return minValue == maxValue?
query.Where(filter.Compose(value => value.Equals(minValue))):
query.Where(filter.Compose(value => value >= minValue && value <= maxValue));
}
return query.Where(maxValue != null ? filter.Compose(value => value.Equals(maxValue)) : filter.Compose(value => value.Equals(minValue)));
}
//copied from https://stackoverflow.com/questions/37602729/convert-linq-expression-obj-obj-prop-into-parent-parent-obj-prop/37602870#37602870
public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(
this Expression<Func<T, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
return Expression.Lambda<Func<T, TResult>>(
second.Body.Replace(second.Parameters[0], first.Body),
first.Parameters[0]);
}
public class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression ex)
{
return ex == @from ? to : base.Visit(ex);
}
}
public static Expression Replace(this Expression ex,
Expression from,
Expression to)
{
return new ReplaceVisitor(from, to).Visit(ex);
}
}
In short, I would like both WhereEqualIfSpecified
and ApplyRangeFilter
to be generic so it can take any type in instead of using overload functions