?. 和?() null 条件运算符 (Visual Basic)

在执行成员访问(Nothing)或索引(?.?())作之前测试左侧作数的值,如果左侧作数的计算结果为 Nothing,则返回 Nothing 。 请注意,在通常返回值类型的表达式中,null 条件运算符返回一个 Nullable<T>

这些运算符可帮助你编写更少的代码来处理 null 检查,尤其是在进入数据结构时。 例如:

' Nothing if customers is Nothing
Dim length As Integer? = customers?.Length

' Nothing if customers is Nothing
Dim first As Customer = customers?(0)

' Nothing if customers, the first customer, or Orders is Nothing
Dim count As Integer? = customers?(0)?.Orders?.Count()

为了进行比较,这些表达式中第一个没有 null 条件运算符的替代代码为:

Dim length As Integer?
If customers IsNot Nothing Then
   length = customers.Length
Else
    length = Nothing
End If

有时,需要根据该对象的布尔成员的值对可能为 null 的对象执行作(如以下示例中的布尔属性 IsAllowedFreeShipping ):

Dim customer = FindCustomerByID(123) 'customer will be Nothing if not found.

If customer IsNot Nothing AndAlso customer.IsAllowedFreeShipping Then
  ApplyFreeShippingToOrders(customer)
End If

可以缩短代码,避免使用 null 条件运算符手动检查 null,如下所示:

Dim customer = FindCustomerByID(123) 'customer will be Nothing if not found.

If customer?.IsAllowedFreeShipping Then ApplyFreeShippingToOrders(customer)

NULL 条件运算符采用最小化求值策略。 如果条件成员访问和索引作链中的一个作返回 Nothing,则链的其余执行将停止。 在下面的示例中,C(E)如果计算结果为,BC不计算A结果Nothing

A?.B?.C?(E)

请注意,如果 Not someStr?.Contains("some string") 计算结果为 Boolean? 其值为 nothingHasValue=false计算的任何其他值,则 else 运行该块。 计算遵循 SQL 计算,其中 null/nothing 不等于任何内容,甚至不等于其他 null/nothing。

另一个用于 null 条件成员访问的用途是以线程安全的方式调用委托,代码要少得多。 下面的示例定义了两种类型:a NewsBroadcaster 和 a NewsReceiver. 消息项由 NewsBroadcaster.SendNews 委托发送到接收方。

Public Module NewsBroadcaster
   Dim SendNews As Action(Of String)

   Public Sub Main()
      Dim rec As New NewsReceiver()
      Dim rec2 As New NewsReceiver()
      SendNews?.Invoke("Just in: A newsworthy item...")
   End Sub

   Public Sub Register(client As Action(Of String))
      SendNews = SendNews.Combine({SendNews, client})
   End Sub
End Module

Public Class NewsReceiver
   Public Sub New()
      NewsBroadcaster.Register(AddressOf Me.DisplayNews)
   End Sub

   Public Sub DisplayNews(newsItem As String)
      Console.WriteLine(newsItem)
   End Sub
End Class

如果调用列表中没有元素 SendNews ,委托 SendNews 将引发一个 NullReferenceException。 在 null 条件运算符之前,如下所示的代码确保委托调用列表不是 Nothing

SendNews = SendNews.Combine({SendNews, client})
If SendNews IsNot Nothing Then
   SendNews("Just in...")
End If

新方法要简单得多:

SendNews = SendNews.Combine({SendNews, client})
SendNews?.Invoke("Just in...")

新方法是线程安全的,因为编译器会生成代码以仅计算 SendNews 一次,从而将结果保留在临时变量中。 需要显式调用 Invoke 该方法,因为没有 null 条件委托调用语法 SendNews?(String)

另请参阅