Null检查Linq中的String.ToLower表达式

Geo*_*kos 8 c# linq null

我有这个方法

private IList<Order> FilterOrders(string filterText)
{
    string filterTextLowerCase = filterText.ToLower();
    var filtered = _orders.Where(order =>
        order.OrderIdFullOrderNumber.ToLower().Contains(filterTextLowerCase) ||
        order.Name.ToLower().Contains(filterTextLowerCase) ||
        order.Status.ToLower().Contains(filterTextLowerCase) ||
        order.TimeRemaining.ToLower().Contains(filterTextLowerCase) ||
        order.Address.ToLower().Contains(filterTextLowerCase) ||
        order.City.ToLower().Contains(filterTextLowerCase) ||
        order.State.Abbrev.ToLower().Contains(filterTextLowerCase) ||
        order.PostalCode.ToLower().Contains(filterTextLowerCase)).ToList();
    return filtered;
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,属性中可能存在nullreference异常,在这个Where表达式中检查null的最佳方法是什么?

Jon*_*oll 10

如果您使用的是C#6,则可以?.在访问对象属性或方法之前添加空检查操作符:order?.State?.ToLower()....

对新的空检查经营者的详细信息.

如果您使用的是较低版本,则必须为每个where子句添加额外的空检查: .Where(order => (order.State != null && order.State.ToLower()....)

  • 注意`bool?`没有`||'运算符.但是,这里的`|`运算符[按预期工作](https://msdn.microsoft.com/en-CA/library/2cf62fcy.aspx),至少如果你之后只接受`true`. (3认同)

Dav*_*dit 6

添加此扩展方法:

public static string NullSafeToLower(this string s)
{
    if (s == null)
    {
        s = string.Empty;
    }
    return s.ToLower();
}
Run Code Online (Sandbox Code Playgroud)

然后将对“ ToLower”的调用替换为对“ NullSafeToLower”的调用。


Cod*_*Hxr 5

即使问题已经回答,另一种选择是:

var myVar = orders.Where(o => (o.SomeProperty ?? "").ToLower() == "someValue");

虽然这不是那么漂亮,但如果您只需要一次或两次,这可能不像扩展方法那样“繁重”,但是如果您需要这样做很多(如您的示例),那么其中之一作为答案列出的扩展方法将为您提供更好的服务。

作为参考,我不得不这样做,因为我当时工作的构建环境还不支持 C# 6.0。如果您在缓慢采用的环境中工作(它发生了!),最好有回退技巧。就是想把这个扔出去。:)


Geo*_*kos 3

不幸的是,我此时无法使用 C# 6.0 功能。

我最终创建了一个扩展方法来过滤列表,与另一个扩展方法 Contains 进行比较,该方法接受 @robert-mckee 建议的 StringComparison 参数并从 @jeppe-stig-nielsen 演示。

public static IList<Order> FilterOrders(this IList<Order> orders, string filterText)
        {
            var filtered = orders.Where(order =>
                order.OrderIdFullOrderNumber.Contains(filterText, StringComparison.OrdinalIgnoreCase) ||
                order.Name.Contains(filterText, StringComparison.OrdinalIgnoreCase) ||
                order.Status.Contains(filterText, StringComparison.OrdinalIgnoreCase) ||
                order.TimeRemaining.Contains(filterText, StringComparison.OrdinalIgnoreCase) ||
                order.Address.Contains(filterText, StringComparison.OrdinalIgnoreCase) ||
                order.City.Contains(filterText, StringComparison.OrdinalIgnoreCase) ||
                order.State.Abbrev.Contains(filterText, StringComparison.OrdinalIgnoreCase) ||
                order.PostalCode.Contains(filterText, StringComparison.OrdinalIgnoreCase)).ToList();
            return filtered;
        }

public static bool Contains(this string source, string value, StringComparison comparison)
        {
            if (string.IsNullOrWhiteSpace(source))
            {
                return false;
            }

            return source.IndexOf(value, comparison) >= 0;
        }
Run Code Online (Sandbox Code Playgroud)