【问题标题】:Does LINQ do short-circuit evaluation in VB.NET?LINQ 是否在 VB.NET 中进行短路评估?
【发布时间】:2012-02-03 12:44:53
【问题描述】:

我们今天在这行代码中遇到了Nullable object must have a value 错误:

list = From x In Me Where x.FooDate.HasValue AndAlso x.FooDate.Value.Date >= barDate

有趣的是,我确信这曾经可以正常工作(并且基础数据中总是存在少量空值)。从逻辑上讲,它对我来说看起来不错。检查HasValueAndAlso 看起来 好像它们会保护我们免受任何 Null 危险。

但似乎突然间他们不是了。我错过了什么吗?

好的,我们可以把它改成这样,这样就消除了错误:

list = From x In Me Where If(x.FooDate.HasValue, x.FooDate.Value.Date >= barDate,False)

但这在我看来不太可读。有什么想法吗?

更新...和忏悔
在简化上面的代码以缩短代码行时,我遗漏了代码的关键部分。原来的问题应该是这样的:

list = From x In Me Where x.FooDate.HasValue AndAlso x.FooDate.Value.Date >= fromDate And x.FooDate.Value.Date <= toDate

由于短路和运算符优先级的规则(如outlined in an answer 到我自己的很久以前的问题),我需要在指令的第二部分周围添加括号,以停止 LINQ 评估第二个 x.FooDate.Value.Date

list = From x In Me Where x.FooDate.HasValue AndAlso (x.FooDate.Value.Date >= fromDate and x.FooDate.Value.Date <= toDate)

感谢这两个答案提供快速测试代码以验证 LINQ 确实遵守 AndAlso 并迫使我更仔细地研究原始问题。

【问题讨论】:

  • 你能用示例数据重现它并向我们展示这段代码吗?
  • 这是 LINQ to Objects,还是您在使用其他 LINQ 提供程序?另外,你能包括整个 LINQ 查询吗?您似乎至少缺少选择部分
  • 这是 LINQ to SQL,还是我返回了一些奇怪的东西(例如,不是 IEnumerable)?
  • @TimSchmelter 刚刚回来,我看到你提供了一个简化的示例,所以我会试试你的......谢谢
  • 我猜这是 LINQ to Objects(我用过的唯一一种),其中 Me 是一个 BindingList(Of Foo)

标签: vb.net linq null short-circuiting


【解决方案1】:

我很确定您的查询是安全的,至少以下示例代码是:

Dim dateList As New List(Of Nullable(Of Date))
For i As Int32 = 0 To 12
    If (i Mod 3 = 0) Then
        dateList.Add(Nothing)
    Else
        dateList.Add(New Date(2012, i, 1))
    End If
Next
Dim july = New Date(2012, 7, 1)
Dim fromJuly = (From m In dateList
      Where m.HasValue AndAlso m.Value.Date >= july).ToList

注意:如果我将AndAlso 替换为And,我会得到你的例外。

所以问题一定出在其他地方。请向我们展示更多您的课程。

【讨论】:

  • 我已经运行了您的代码并得到了与您相同的结果,所以您是对的,问题一定出在其他地方。我会继续挖掘
  • @hawbsl:与其在第二个条件上添加括号,不如直接使用AndAlso 而不是And?还是我误解了“运算符优先级”问题?
【解决方案2】:

它应该工作。我编写了这段代码,它对我来说很好,即使 barDate 设置为 Nothing

Sub Main()

    Dim barDate As Nullable(Of DateTime) = Nothing

    Dim List = From x In GetDates() Where x.FooDate.HasValue AndAlso x.FooDate.Value.Date > barDate

    Console.WriteLine(List.Count())

End Sub

Function GetDates() As List(Of Foo)
    Dim l = New List(Of Foo)
    l.Add(New Foo With {.FooDate = DateTime.Now})
    l.Add(New Foo)
    Return l
End Function

Class Foo
    Private m_fooDate As DateTime?
    Public Property FooDate() As DateTime?
        Get
            Return m_fooDate
        End Get
        Set(ByVal value As DateTime?)
            m_fooDate = value
        End Set
    End Property

End Class

【讨论】:

    猜你喜欢
    • 2016-02-19
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 2013-08-25
    相关资源
    最近更新 更多