1

I have followed several threads on SO and other websites and am still having difficulty.

I have the following code:

public static IQueryable<TSource> Between<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, TKey low, TKey high, bool inclusive = true) where TKey : IComparable<TKey>
    {
        var key = Expression.Invoke(keySelector, keySelector.Parameters.ToArray());

        var intLow = int.Parse(low.ToString());
        var intHigh = int.Parse(high.ToString());

        var lowerBound = (inclusive)
                  ? Expression.GreaterThanOrEqual(key, Expression.Constant(intLow, typeof(int)))
                  : Expression.GreaterThan(key, Expression.Constant(intLow, typeof(int)));

        var upperBound = (inclusive)
                  ? Expression.LessThanOrEqual(key, Expression.Constant(intHigh, typeof(int)))
                  : Expression.LessThan(key, Expression.Constant(intHigh, typeof(int)));

        var and = Expression.AndAlso(lowerBound, upperBound);
        var lambda = Expression.Lambda<Func<TSource, bool>>(
                        and, keySelector.Parameters);

        return source.Where(lambda);
    }

If I call this function with the following code:

lowValue = 2;
highValue = 11;

var sampleData = BuildSampleEntityInt(1, 3, 10, 11, 12, 15);
var query = sampleData.Between(s => s.SampleSearchKey, lowValue, highValue, false);
Assert.AreEqual(2, query.Count());

It works. But If I use Strings instead like:

lowValueString = "3";
highValueString = "10";

var sampleData = BuildSampleEntityString(1, 3, 10, 11, 12, 15);
var query = sampleData.Between(s => s.SampleSearchKey, lowValueString , highValueString);
Assert.AreEqual(2, query.Count());

or convert the strings to integers first

lowValueString = "3";
highValueString = "10";
int.TryParse(lowValueString, out lowValue);
int.TryParse(highValueString, out highValue);


var sampleData = BuildSampleEntityString(1, 3, 10, 11, 12, 15);
var query = sampleData.Between(s => s.SampleSearchKey, lowValue, highValue);
Assert.AreEqual(2, query.Count());

I get the following error:

{"The binary operator GreaterThanOrEqual is not defined for the types 'System.String' and 'System.Int32'."}

When the following line runs.

var lowerBound = (inclusive)
             ? Expression.GreaterThanOrEqual(key, Expression.Constant(intLow, typeof(int)))
             : Expression.GreaterThan(key, Expression.Constant(intLow, typeof(int)));

Can anyone point out what needs to be changed?

I have added the following:

 private IQueryable<SampleEntityInt> BuildSampleEntityInt(params int[] values)
    {
        return values.Select(
               value =>
               new SampleEntityInt() { SampleSearchKey = value }).AsQueryable();
    }
4
  • Thanks for everyone looking, found the issue........I you look closely at the code you will notice that when the sample data is created two different functions are used. One creates int[] whilst the other creates string[]. Changed them both to be int[] and now ok.
    – gilesrpa
    Commented Dec 21, 2016 at 15:07
  • This did not fix the problem
    – gilesrpa
    Commented Dec 22, 2016 at 14:19
  • is there a reason why you build it with expressions instead of using simple lambdas?
    – MistyK
    Commented Dec 30, 2016 at 13:00
  • Wait... your data is numbers... Why do you need to be able to compare the numbers to strings? Commented Jan 1, 2017 at 9:52

1 Answer 1

3

The problem here is that you define two generic type attributes: TSource and TKey, but actually you have three types of them. It works, if TKey is the same type as lowValue and highValue (both are int), but it doesn't work if lowValue and highValue are of the type string and TKey is still int.

Code you provided works fine, if i add the third generic parameter TLowHigh, that's a type of your low/hight arguments :

public static IQueryable<TSource> Between<TSource, TKey, TLowHigh>(
      this IQueryable<TSource> source, 
      Expression<Func<TSource, TKey>> keySelector, 
      TLowHigh low, 
      TLowHigh high,
      bool inclusive = true) 
          where TKey : IComparable<TKey>
{
    var key = Expression.Invoke(keySelector, keySelector.Parameters.ToArray());

    var intLow = int.Parse(low.ToString());
    var intHigh = int.Parse(high.ToString());

    var lowerBound = (inclusive)
            ? Expression.GreaterThanOrEqual(key, Expression.Constant(intLow, typeof(int)))
            : Expression.GreaterThan(key, Expression.Constant(intLow, typeof(int)));

    var upperBound = (inclusive)
            ? Expression.LessThanOrEqual(key, Expression.Constant(intHigh, typeof(int)))
            : Expression.LessThan(key, Expression.Constant(intHigh, typeof(int)));

    var and = Expression.AndAlso(lowerBound, upperBound);
    var lambda = Expression.Lambda<Func<TSource, bool>>(
                    and, keySelector.Parameters);

    return source.Where(lambda);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.