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

时间:2015-12-10 21:39:45

标签: 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;
}

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

6 个答案:

答案 0 :(得分:9)

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

有关新的null检查运算符的详细信息,请参阅this

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

答案 1 :(得分:4)

不确定这是漂亮还是丑陋。它确实为每个订单创建了一个临时数组,但它避免了大量的重复。

mypassword{HASHSTRING}

答案 2 :(得分:4)

添加此扩展方法:

public static string NullSafeToLower(this string s)
{
    if (s == null)
    {
        s = string.Empty;
    }
    return s.ToLower();
}

然后通过调用“NullSafeToLower”替换对“ToLower”的调用。

答案 3 :(得分:3)

即使这个问题已经得到解答,另一种选择就是:

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

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

作为参考,我必须这样做,因为我当时正在处理的构建环境还不支持C#6.0。如果你在一个缓慢采用的环境中工作,那么有一个后备技巧是很好的(它发生了!)。只是想把它扔出去。 :)

答案 4 :(得分:2)

不幸的是,此时我无法使用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;
        }

答案 5 :(得分:1)

添加以下扩展方法。

public static class StringHelper
{
    public static string SafeToLower(this string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return string.Empty;
        }
        return value.ToLower();
    }
}

您的代码将成为以下内容。

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