使用可选的搜索子句执行LINQ查询

时间:2010-07-16 17:47:55

标签: c# linq short-circuiting

我有一个页面,您可以搜索人员。他们可以获得所有人的列表,也可以按照某个或多个名称等标准对其进行过滤。

到目前为止,我一直在尝试使用this question中详述的技术。

所以我的代码看起来像

string firstname=...
string lastname=...

var people=from p in People.All()
           where (firstname==null || firstname.ToLower()==p.FirstName.ToLower()) &&
                 (lastname==null || lastname.ToLower()==p.LastName.ToLower())
           select p;

构建查询时遇到空引用错误,但firstname和lastname都为null。删除where子句可以消除错误。

为什么这不起作用? C#是否尝试评估where子句的每个部分的第二部分?它不应该因为OR的短路而对吗?

4 个答案:

答案 0 :(得分:1)

您无需使用ignoreCase

来调用ToLower()使用string.compare
string.Compare(firstName, p.FirstName, true) 

答案 1 :(得分:1)

使用string.Equals:

from p in People.All()
where (firstname == null || string.Equals (firstname, p.FirstName, StringComparison.InvariantCultureIgnoreCase)) &&
      (lastname == null || string.Equals (lastname, p.LastName, StringComparison.InvariantCultureIgnoreCase))
select p

这不仅可以避免null问题,而且还会强制您指定字符串比较类型(这是一件好事)。换句话说,您在执行不区分大小写的比较时指定是否使用特定于本地或不变文化的规则。

答案 2 :(得分:0)

在调用ToLower之前确保它不为空:

(firstname==null || (firstname!= null && firstname.ToLower()==p.FirstName.ToLower()))

答案 3 :(得分:0)

当两者都为空时它不起作用,因为语句的第一部分将评估为true,不允许评估的短路。为什么不使用等价规则来翻转语句?

(firstName != null && firstName.ToLower() == p.firstName.ToLower()) 
编辑:我写了以下内容并在LINQPad 4中成功运行,没有任何问题。我假设对People.All()的调用只返回带有完整记录集的IQueryable<People>?也许在这里发布您的异常文本,以便我们可以看到您是否有意外错过了什么?

void Main()
{
    string a = null;
    string b = null;
    var peeps = new List<Person> { 
        new Person { 
            FirstName = "John",
            LastName = "Connor"
        },
        new Person { 
            FirstName = "Sarah",
            LastName = "Connor",
        },
        new Person { 
            FirstName = "Cletus",
            LastName = "Handy"
        }
    };

    var somePeeps = from p in peeps
        where (a == null || a.ToLower() == p.FirstName.ToLower()) 
            && (b == null || b.ToLower() == p.LastName.ToLower())
        select p;

    somePeeps.Dump();

}

public class Person
{
    public string FirstName { get; set;}
    public string LastName { get; set;}
}