通过泛型构建动态查询

时间:2019-01-17 03:50:20

标签: c# generics expression

我建立了一个静态类,并尝试使用泛型参数实现动态查询。下面是我的接口定义和类定义:

public interface IRangeValue<T> where T : struct
{
    Nullable<T> High{get;set;}
    Nullable<T> Low { get; set; }
}

public class DataRangeT<T> : IRangeValue<T>
    where T : struct
{
    Nullable<T> _high;
    Nullable<T> _low;
    public Nullable<T> High { get { return _high; } set { _high = value; } }
    public Nullable<T> Low { get { return _low; } set { _low = value; } }

}

然后,我构建了一个静态方法来实现动态查询:

public static class ExpressionHelperT<K>
    where K : struct
{
    public static Expression<Func<T, bool>> RangeCompare<T>(Expression<Func<T, K>> selector, IRangeValue<K> patten)
    {
        Expression<Func<T, bool>> predicate = PredicateBuilder.True<T>();
        if (patten.High.HasValue)
        {
            predicate = predicate.And<T>(Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(selector, Expression.Constant(patten.High.Value, typeof(K)))));
        }
        if (patten.Low.HasValue)
        {
            predicate = predicate.And<T>(Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(selector, Expression.Constant(patten.Low.Value, typeof(K)))));
        }
        return predicate;
    }

}

方法And定义如下:

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
    }

现在,我尝试测试我的RangeCompare<T>方法,然后调用如下方法:

class Program
{
    static void Main(string[] args)
    {
        DataRangeT<DateTime> dataRange = new DataRangeT<DateTime>();

        dataRange.High = null;
        dataRange.Low = DateTime.Today;

        List<DateTime> dates = new List<DateTime>();
        dates.Add(new DateTime(2018, 1, 1));
        dates.Add(new DateTime(2018, 2, 1));
        dates.Add(new DateTime(2018, 3, 1));
        dates.Add(new DateTime(2018, 4, 1));
        dates.Add(new DateTime(2018, 5, 1));
        dates.Add(new DateTime(2018, 6, 1));
        dates.Add(new DateTime(2018, 7, 1));
        dates.Add(new DateTime(2018, 8, 1));
        dates.Add(new DateTime(2018, 9, 1));

        List<DateTime> results = dates.Where<DateTime>(ExpressionHelperT<DateTime>.RangeCompare<DateTime>(c => c.Date, dataRange)).ToList();

        foreach (DateTime dt in results)
        {
            Console.WriteLine(dt.ToShortDateString());
        }
        Console.ReadLine();
    }
}

但是compliter总是告诉我:

Can't convert System.Collections.Generic.List<System.DateTime>”to“System.Linq.ParallelQuery<System.DateTime>”
Can't convert“System.Linq.Expressions.Expression<System.Func<System.DateTime,bool>>”to“System.Func<System.DateTime,int,bool>”

为什么?

1 个答案:

答案 0 :(得分:0)

您的第一个例外与您发布的代码无关

  

无法转换   System.Collections.Generic.List <>”到“ System.Linq.ParallelQuery <>”

您的第二个例外是自我解释

IEnumerbale没有这样的方法签名

Where<TSource>(this IEnumerable<TSource> source, Expression<Func<TSource, bool>> predicate)

检查自己的Enumerable.Where Method

如果您希望Where支持 Expression ,则需要使用将其转换为IQueryable的方式,请参见here

IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)

解决

使用AsQueryable 扩展方法转换为IQueryable

var results = dates.AsQueryable()
                   .Where(ExpressionHelperT<DateTime>.RangeCompare<DateTime>(c => c.Date, dataRange)).ToList();