2016-12-21 13 views
1

Я следил за несколькими потоками на SO и других сайтах, и у меня все еще есть трудности.Linq Выражения. Эквивалент больше, чем для строк

У меня есть следующий код:

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); 
    } 

Если я называю эту функцию с помощью следующего кода:

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()); 

Он работает. Но если я использую вместо строк, как:

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()); 

или преобразовывать строки в целые числа первых

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()); 

Я получаю следующее сообщение об ошибке:

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

При выполнении следующей строки.

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

Может ли кто-нибудь указать, что нужно изменить?

Я добавил следующее:

private IQueryable<SampleEntityInt> BuildSampleEntityInt(params int[] values) 
    { 
     return values.Select(
       value => 
       new SampleEntityInt() { SampleSearchKey = value }).AsQueryable(); 
    } 
+0

Спасибо каждому, кто ищет, нашел этот вопрос ....... . Я внимательно смотрю на код, который вы заметите, что при создании выборки данных используются две разные функции. Один создает int [], а другой создает строку []. Изменено их как int [], и теперь нормально. – gilesrpa

+0

Это не исправить проблему – gilesrpa

+0

есть ли причина, почему вы строите ее с помощью выражений вместо использования простых лямбда? – MistyK

ответ

3

Проблема здесь состоит в том, что вы определили два универсальных типа атрибутов: TSource и TKey, но на самом деле у вас есть три типа них. Это работает, если TKey того же типа, как и lowValuehighValue (оба int), но он не работает, если lowValue и highValue имеют тип string и TKey еще int.

Код, который при условии отлично работает, если добавить третий параметр универсального TLowHigh, это тип ваших низких аргументов/высокими:

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); 
}