?. 和 ?() 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

有时你需要根据该对象上的布尔成员的值对可能为空的对象执行操作(如以下示例中的布尔属性 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,则该链其余部分的执行将停止。 在以下示例中,如果 ABC 计算结果为 Nothing,则不计算 C(E)

A?.B?.C?(E)

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

NULL 条件成员访问的另一个用途是使用非常少的代码以线程安全的方式调用委托。 下面的示例定义了两种类型:NewsBroadcasterNewsReceiver。 新闻项目由 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)

另请参阅