Linq lambda表达式中的布尔短路评估

Bru*_*ill 6 c# linq lambda linq-to-sql

我有以下Linq lambda表达式:

private IEnumerable<SubjectSelectorSubjectGroup> GetSubjectList()
{
    User user = db.Users.Find(WebSecurity.CurrentUserId);
    return db.RequiredSubjects.Where(r => !r.Subject.Name.Contains("Home"))
                              .GroupBy(r => r.Subject)
                              .OrderByDescending(r => r.Count())
                              .Select(r => new SubjectSelectorSubjectGroup()
                              {
                                  SubjectId = r.Key.SubjectId,
                                  SubjectName = r.Key.Name,
                                  IsInFavourites = HttpContext.Current.Request.IsAuthenticated &&
                                                  (user.Elective1 != null && user.Elective1.SubjectId == r.Key.SubjectId ||
                                                   user.Elective2 != null && user.Elective2.SubjectId == r.Key.SubjectId ||
                                                   user.Elective3 != null && user.Elective3.SubjectId == r.Key.SubjectId),
                                  Occurrences = r.Count()
                              });
}
Run Code Online (Sandbox Code Playgroud)

当用户未登录时user,此函数中的变量为null.这不应该是一个问题,因为短路布尔评估应该处理这个问题.问题是,它没有!相反,System.NullReferenceException抛出了一个.

当用户为null时HttpContext.Current.Request.IsAuthenticated返回false.我通过注释引用user变量的括号部分来检查这一点,然后表达式正确评估.

有没有人知道为什么在这种情况下Linq to Sql尝试取消引用user变量时它实际上是不必要的呢?有没有人解决这个问题?

And*_*bel 5

整个表达式被转换为SQL并进行评估,这意味着&&运算符不会按预期短路.

您可以通过构建ElectiveX.SubjectId要搜索的列表或数组来解决问题,然后tmpList.Contains(r.Key.SubjectId)在查询中使用.这将被翻译成WHERE IN (...)SQL表达式.

  • 谢谢,Anders,解释和建议使用列表.我按照你的建议使用列表解决了它.我将把代码作为我的解决方案的代码放在一个单独的答案中,但会将你的答案标记为正确.谢谢你的帮助. (2认同)
  • 我还观察到短路没有按预期工作。我不认为将 C# 表达式转换为 SQL 的事实,在幕后,免除了 Microsoft 遵守 [C# 语言规范](http://www.microsoft.com/en-us/download) 的义务/details.aspx?id=7029),参见 7.12 条件逻辑运算符。 (2认同)