【问题标题】:Catch NullReferenceException or test for Nothing first?捕获 NullReferenceException 或先测试 Nothing?
【发布时间】:2010-11-12 11:14:25
【问题描述】:

我们有一个属性,它的工作是查找描述。如果查找失败,它应该显示一个空字符串。

所以我们可以像这样对属性进行编码:

If foo.bar Is Not Nothing Then
  Return foo.bar.Description
Else
  Return String.Empty
End If

但这涉及执行 foo.bar 两次,如果这样做很昂贵,最好这样:

Dim b As bar = foo.bar
If b IsNot Nothing Then
  Return b.Description
Else
  Return String.Empty
End If

但实际上,我们想要做的只是将任何类型的错误视为空描述。所以在某些方面这更简单:

Try
  Return foo.bar.Description
Catch e As NullReferenceException
  Return String.Empty
End Try

但是仅捕获和忽略错误是否存在任何问题(性能、纯度、其他?)?

您有时会读到抛出异常很昂贵,但我不确定作者是否意味着使用 Throw 关键字(我没有这样做)构建异常很昂贵,或者他是否意味着允许发生异常是很昂贵的(就像我会做的那样)。

【问题讨论】:

    标签: vb.net nullreferenceexception


    【解决方案1】:

    If 肯定会测试 Nothing 而不是在这里依赖异常。您的代码表明foo.barNothing 的场景是预期场景,而不是异常。这样就给出了答案。

    抛出异常是一项相对昂贵的操作(从性能角度来看)。无论您是在代码中抛出它,还是在库代码中抛出它,情况都是如此;这是完全相同的操作。但是,除非我有一个真实的、可衡量的、关键的业务案例,否则我不会因为性能原因而抛出异常。

    在我看来,这主要是表明意图的问题;通过测试Nothing 并优雅地采取行动,您的代码表达了这样一个事实,即发生这种情况并不奇怪。

    如果您担心两次执行foo.bar 的性能,首先要做的是找出是否真的如此。如果是这样,可能有解决方法(您的代码示例已经包含建议)。

    【讨论】:

      【解决方案2】:

      我会采用这种方法:

      Dim b As bar = foo.bar
      If b IsNot Nothing Then
        Return b.Description
      Else
        Return String.Empty
      End If
      

      如果以后发现自己经常重复代码的同一部分,可以将此查找包装到一个通用函数中,例如:

      Private Function GetPropertyOrStringEmptyIfNothing(barObj As bar, propSelector As Func(Of bar, String))
        If barObj IsNot Nothing Then
          Return propSelector(barObj)
        Else
          Return String.Empty
        End If
      End Function
      

      这是一个用法示例:

      GetPropertyOrStringEmptyIfNothing(foo.bar, Function(x) x.Description)
      

      假设您在当前范围内声明了一个类似的类,它将起作用:

      Class bar
        Public Description As String
      End Class
      

      就捕获异常的成本而言,here is a link to my answer on a different question。它让您了解捕获异常如何影响调试性能以及发布版本的性能。从语义上讲,您最好避免在非异常情况下抛出异常,正如其他答案中已经提到的那样。

      【讨论】:

        【解决方案3】:

        当您期望它作为受控条件时,您应该始终尝试不进行任何测试,仅在可能的情况下使用捕获来处理不需要的错误(我广泛使用不需要的错误,因为某些错误会产生想要的结果)。处理空字符串而不捕获异常的能力是存在的,所以使用它。

        在名为IsNullOrEmptyIsNullOrWhiteSpace 的String 类类型中使用空字符串测试函数:

            Public Shared Sub Main()
        
                Dim f As String
                Dim b As String
        
                Dim emptyResponseString As String = "I was empty"
        
                'Foo will return a Null String'
        
                f = foo()
        
                'Bar will return an instantiated String'
        
                b = bar()
        
                If String.IsNullOrEmpty(f) Then
                    Console.Out.WriteLine("foo(): " & emptyResponseString)
                Else
                    Console.Out.WriteLine("foo(): " & f)
                End If
        
                If String.IsNullOrEmpty(b) Then
                    Console.Out.WriteLine("bar(): " & emptyResponseString)
                Else
                    Console.Out.WriteLine("bar(): " & b)
                End If
        
            End Sub
        
            Public Shared Function foo() As String
                Return Nothing
            End Function
        
            Public Shared Function bar() As String
                Return "I am not empty!"
            End Function
        

        这将允许您将异常处理留给意外异常(应该是 ^^)

        根据您的选择,第二个最接近我的建议,将您的函数结果放入一个保持变量中,然后使用 String.IsNullOrEmpty 测试此变量,或者如果您想包含空格检查,则使用 String.IsNullOrWhiteSpace (这也测试空字符串)。

        这是运行的代码:

        http://ideone.com/CelDe

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-14
          • 2015-03-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-28
          相关资源
          最近更新 更多