2017-05-05 77 views
0

我遇到了一个问题,我想返回匹配结果的地方,如果我试图匹配的其中一个属性为空,我会得到一个错误。linq空值where子句

if (!string.IsNullOrEmpty(searchString)) 
    { 
     Infos = Infos.Where(
      x => 
      x.FirstName.ToLower().Contains(searchString) || 
      x.LastName.ToLower().Contains(searchString) || 
      x.ContractNum.ToLower().Contains(searchString) || 
      x.VIN.ToLower().Contains(searchString) || 
      x.Claim.InitiatedBy.ToLower().Contains(searchString) 
     ).ToList(); 
    } 

如果ContractNumVIN,例如,是空值,则它会引发错误。我不知道如何检查它们中的一个在linq查询中是否为null。

+1

LINQ表达式与常规布尔表达式没有区别,因此检查null是一样的。 –

回答

1

检查属性是比较它,它是我知道

if (!string.IsNullOrEmpty(searchString)) 
     { 
      Infos = Infos.Where(
       x => 
       (!String.IsNullOrEmpty(x.FirstName) && x.FirstName.ToLowerInvariant().Contains(searchString)) || 
       (!String.IsNullOrEmpty(x.LastName) && x.LastName.ToLowerInvariant().Contains(searchString)) || 
       (!String.IsNullOrEmpty(x.ContractNum) && x.ContractNum.ToLowerInvariant().Contains(searchString)) || 
       (!String.IsNullOrEmpty(x.VIN) && x.VIN.ToLowerInvariant().Contains(searchString)) || 
       (x.Claim != null && !String.IsNullOrEmpty(x.Claim.InitiatedBy) && x.Claim.InitiatedBy.ToLowerInvariant().Contains(searchString)) 
      ).ToList(); 
     } 

EXTRA的唯一途径之前null或空:我添加的Claim财产进行检查,以确保它看起来不是空的InitiatedBy

额外2:使用内建函数IsNullOrEmpty来比较str编号为""null所以代码更清晰。

额外3:使用ToLowerInvarianthttps://msdn.microsoft.com/en-us/library/system.string.tolowerinvariant(v=vs.110).aspx)所以无论文化如何,降低行动都会发挥相同的作用。

+0

我喜欢这个答案最好的完整性,甚至尽管我并不真正关心文化。 Reshaper建议您将最后两个顺序检查合并到:'(!string.IsNullOrEmpty(x.Claim?.InitiatedBy)&& x.Claim.InitiatedBy.ToLowerInvariant()。Contains(searchString))' –

+1

I同意全能Resharper对此。 – Muffun

+0

我可能会提取一个方法,以避免重复调用'string.IsNullOrEmpty()'和'.ToLowerInvariant()。Contains()'以覆盖测试条件发生变化的情况。根据域,甚至可以选择使对象本身公开所述方法(如果适当的话)以进一步减少可能的重复。 –

5

您可以添加明确的null检查:

Infos = Infos.Where(
     x => 
     (x.FirstName != null && x.FirstName.ToLower().Contains(searchString)) || 
     (x.LastName != null && x.LastName.ToLower().Contains(searchString)) || 
     (x.ContractNum != null && x.ContractNum.ToLower().Contains(searchString)) || 
     (x.VIN != null   && x.VIN.ToLower().Contains(searchString)) || 
     (x.Claim != null  && x.Claim.InitiatedBy != null && x.Claim.InitiatedBy.ToLower().Contains(searchString)) 
    ).ToList(); 
+0

你可以尝试这样的事情。它将允许null和非null。 (string.Equals(x.ContractNum,string。空)|| x.ContractNum.Trim()。Contains(“searchString”)) –

+0

@JeanB当然,有几种不同的方法来解决它。随意添加一个不同的答案。 –

+0

我的想法最近真的被高估了,我不确定为什么我没有这样做/记住如何做到这一点。我一直试图放?所有的地方,它不断给我错误。这样一个简单的修复。 –

1

你可以使用??与可接受值来代替它。

(x.ContractNum??"").ToLower() 
+2

请不要。不要这样做。只要定期进行空检查。 –

+1

区别是什么? – ThatChris

+1

无用'ToLower()'和后续调用。 –

1

我会用空条件运算?,但是这会,返回null的bool?所以你需要适当地处理这个问题。

如何做到这一点的一些例子:

x?.FirstName?.ToLower().Contains(searchString) == true; 
x?.FirstName?.ToLower().Contains(searchString) ?? false; 
+1

最后的选择是最好的恕我直言。 –

+0

这只适用于C#6+。但是,这也是一个不错的选择:) –

+2

@PatrickHofman我通常更喜欢最后一个=='真正'和相当于我读错了。 – TheLethalCoder

2

你有多种选择,首先是做对空和其他选项直接检查是使用空传播运营商。

x.FirstName != null && x.FirstName.ToLower().Contains(searchString) 

x.FirstName?.ToLower()?.Contains(searchString) == true 

但我建议你使用代替IndexOfContains的情况下 大小写的比较。

类似:

x.FirstName?.IndexOf(searchString, StringComparison.CurrentCultureIgnoreCase) > 0) 
+0

@TimSchmelter,谢谢蒂姆。 – Habib

+0

建议使用IndexOf的好处是什么? –

+0

@BarryFranklin,http://haacked.com/archive/2012/07/05/turkish-i-problem-and-why-you-should-care.aspx/ – Habib

1

的另一种方法,以保持比较逻辑在一个地方使用属性的子集,并检查这些:

Infos = Infos.Where(i=> 
    new[] {i.FirstName,i.LastName,i.ContractNum /*etc*/} 
    .Any(w=> w?.ToLower().Contains(searchString) ?? false)) 
    .ToList(); 

(它不会读出所有属性,但不应该花费不多性能和获得很大的可维护性)

+0

构建一个新的数组毫无意义,在我看来,可读性会下降,可能需要更长的时间。我相信它应该是'选择'而不是'Where'。 – TheLethalCoder

+0

@TheLethalCoder可读性可能是有争议的,但不是重复每个独立属性的逻辑,而是将它保留在一个地方。 Imho增加了可读性。 (并且确保人们不能忘记一个属性的“?”)无论如何,Where是正确的:该阵列仅用于使用它的Any以及匹配时的短路 –

+0

关于性能:是,这在更大的列表中以毫秒为单位更重,但是如果这是一个问题,我会创建某种迭代器,并将检查逻辑保存在一个地方 –