Как безопасно .ToLower (). Contains () на возможное нулевое свойство - PullRequest
1 голос
/ 22 октября 2019
private Expression<Func<ProductDto, bool>> FilterData(ProductRequest searchQuery)
{
    string searchString = !string.IsNullOrEmpty(searchQuery.SearchString)
           ? searchQuery.SearchString.ToLower()
           : string.Empty;

    return f => ((f.ProductName.ToLower().Contains(searchString))
                || (f.ProductParentName.ToLower().Contains(searchString)));
}

Иногда ProductName или ProductParentName равны нулю, поэтому мое приложение вылетает.

Я пытался использовать условный оператор нулевой функции C # 6.0, поэтому я написал что-то вроде этого:

return f => ((f.ProductName?.ToLower().Contains(searchString))
                    || (f.ProductParentName?.ToLower().Contains(searchString)));

Но чем я получил сообщение:

оператор ||не может быть применен к операндам типа 'bool' и 'bool?'

Как я могу гарантировать, что смог бы выполнить, даже если некоторые реквизиты здесь нулевые?

Спасибо

Приветствия

Ответы [ 4 ]

1 голос
/ 22 октября 2019

Иногда ProductName или ProductParentName имеют значение null, поэтому мое приложение аварийно завершается.

Предполагается, что оно выполняется на стороне сервера, а не в памяти,

Сохраняйте это простым и проверяйтедля нулевого значения до применения функций.

return f => ((f.ProductName != null && f.ProductName.ToLower().Contains(searchString))
            || (f.ProductParentName != null && f.ProductParentName.ToLower().Contains(searchString)));

Фреймворк должен быть в состоянии перевести это на SQL.

1 голос
/ 22 октября 2019

Обновление: Невозможно использовать нуль-распространяющий оператор из лямбды дерева выражений (я также не смог заставить его работать, используя ToLower). Вы можете выполнить рефакторинг к чему-то подобному ниже, используя StringComparison.OrdinalIgnoreCase, чтобы выполнить сравнение без учета регистра:

return f => (f.ProductName != null)
          ? (f.ProductName.Contains(searchString, StringComparison.OrdinalIgnoreCase) 
             || f.ProductParentName.Contains(searchString, StringComparison.OrdinalIgnoreCase) )
          : false;

Исходный ответ

Вы можете объединить этос оператором null-coalescing (??).

return f => ( (f.ProductName?.ToLower().Contains(searchString) ?? false)
           || (f.ProductParentName?.ToLower().Contains(searchString) ?? false));

f.ProductName?.ToLower() использует оператор null-conditional (.?), который возвращает null, когда ProductName равно null, поэтому вам нужно вернуть значение по умолчанию, которое обеспечивает оператор слияния.

0 голосов
/ 22 октября 2019

Вы можете использовать IndexOf вместо Contains, поскольку он предоставляет аргумент типа сравнения, который можно указать без учета регистра. Как правило, это лучше, чем вызывать ToLower для строк (см. в этой статье для получения дополнительной информации):

var search = searchQuery.SearchString ?? string.Empty;

return f => 
    f.ProductName?.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1 ||
    f.ProductParentName?.IndexOf(search, StringComparison.OrdinalIgnoreCase) > -1;

Вам также не нужно выполнять объединение, если значение равноnull, так как -1 обрабатывается компилятором как Nullable<int>, и он вернет false, если левая сторона равна null.

0 голосов
/ 22 октября 2019

Конечно, есть много способов решить эту проблему, и моя первая попытка не сработала.

Так как возвращаемое выражение не может использовать локальную функцию или оператор нулевого распространения, старый тест может подойти:

private Expression<Func<ProductDto, bool>> FilterData(ProductRequest searchQuery)
{
    string searchString = !string.IsNullOrEmpty(searchQuery.SearchString)
           ? searchQuery.SearchString.ToLower()
           : string.Empty;

    return f => string.IsNullOrEmpty(searchString)
       || (!string.IsNullOrEmpty(f.ProductName) && f.ProductName.ToLower().Contains(searchString))
       || (!string.IsNullOrEmpty(f.ParentProductName) && f.ParentProductName.ToLower().Contains(searchString));
}

Я использовал ту же сигнатуру функции, что и вы, и компилятор, похоже, рад этому, хотя она определенно выглядит загроможденной.

Обязательно настройте первую часть return чтобы отразить, что делать, если строка поиска пуста: та, которую я использовал, предполагает, что пустая строка поиска соответствует всему - редактировать по вкусу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...