如何在可能为null的属性上安全地.ToLower()。Contains()

时间:2019-10-21 23:19:42

标签: c# entity-framework linq lambda .net-core

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

有时ProductNameProductParentName为空,所以我的应用程序崩溃了。

我尝试使用C#6.0功能null条件运算符,所以我写了这样的东西:

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

但是我没有收到消息:

  

操作员||不能应用于类型为'bool'的操作数,并且   'bool?'

即使这里的一些道具为空,我如何确保可以执行?

谢谢

欢呼

4 个答案:

答案 0 :(得分:1)

更新:不能在表达式树lambda中使用空值传播运算符(我也无法使用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运算符(.?),当nullProductName时返回null,因此您需要返回默认值值是null推算运算符提供的。

答案 1 :(得分:1)

  

有时ProductName或ProductParentName为null,因此我的应用程序崩溃了。

假设它是在服务器端而不是内存中执行的,

保持简单并在应用函数之前检查是否为空。

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

该框架应该能够将其转换为SQL。

答案 2 :(得分:0)

肯定有很多方法可以解决此问题,而我的第一次尝试没有用。

由于返回的表达式不能使用局部函数或null传播运算符,因此老式的测试可能会这样做:

response

我使用了与您相同的函数签名,尽管看起来确实很混乱,但编译器对此感到满意。

请确保调整catch的第一部分以反映搜索字符串为空的情况:我使用的那个假设一个空的搜索字符串与 everything 匹配-编辑为味道。

答案 3 :(得分:0)

您可以使用IndexOf代替Contains,因为它提供了一个比较类型参数,您可以将其指定为不区分大小写。通常,这比在字符串上调用ToLower更好(有关更多信息,请参见this article):

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>,并且它将返回{{1 }},如果左侧是false