2010-11-12 11 views
8

Tenemos una propiedad cuyo trabajo es buscar una descripción. Si la búsqueda falla, debe mostrar una cadena vacía.¿Capturas NullReferenceException o pruebas para Nothing primero?

por lo que podemos codificar la propiedad como esta:

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

Pero eso implica la ejecución de foo.bar dos veces, y si al hacerlo es caro, es probable que sea mejor así:

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

Pero realmente todo lo que queremos hacer es tratar cualquier tipo de error como una descripción vacía. Así que en cierto modo esto es más simple:

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

¿Pero hay algún problema (rendimiento, la pureza, la otra?) Con sólo la captura e ignorando el error?

A veces se leen es caros de producir una excepción pero no estoy seguro de si el autor quiere decir que es caro de construir en las excepciones utilizando el Throw palabra clave (que no estoy haciendo) o si él quiere decir que es caro para permitir excepciones ocurrir (como yo estaría haciendo).

Respuesta

8

Si definitivamente probar para Nothing en lugar de confiar en las excepciones aquí. Su código indica que el escenario donde foo.bar es Nothing es un escenario esperado, y no excepcional uno. Ese tipo de da la respuesta.

Lanzar una excepción es una operación relativamente costosa (desde una perspectiva de rendimiento). Este es el caso independientemente de si lo está arrojando en su código, o si está arrojado en el código de la biblioteca; es exactamente la misma operación. Sin embargo, no evitaría lanzar excepciones por motivos de rendimiento a menos que tuviese un caso comercial real, medido y crítico.

En mi opinión, esto es principalmente una cuestión de mostrar intención; probando para Nothing y actuando con gracia sobre eso, su código expresa el hecho de que esto no es algo extraño que ocurra.

Si le preocupa el rendimiento en la ejecución de foo.bar dos veces, lo primero que debe hacer es averiguar si ese es realmente el caso. Si es así, probablemente haya formas de resolver eso (su muestra de código ya contiene una sugerencia).

+0

+1 Una respuesta excelente y bien explicada. Y 100% correcto. –

2

Siempre debe intentar probar sin problemas cuando lo espera como una condición controlada, solo use capturas cuando sea posible para manejar los errores no deseados (uso ampliamente no deseado ya que algunos errores producen resultados deseados). La capacidad de manejar cadenas nulas sin capturar una excepción está allí así que úsala.

uso de una función de prueba de cadena vacía en el tipo de clase de cadena llamado IsNullOrEmpty o IsNullOrWhiteSpace:

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 

Esto le permitirá salir de su Tratamiento de excepciones para las excepciones inesperadas (como debe ser ^^)

En perspectiva de sus elecciones, la segunda es la más cercana a lo que recomendaría, coloque el resultado de sus funciones en una variable de retención, luego pruebe esta variable usando String.IsNullOrEmpt y o si desea incluir espacios en blanco marcando String.IsNullOrWhiteSpace (esto también prueba vacío str ings también).

Aquí es el código de ejecución:

http://ideone.com/CelDe

2

Me gustaría ir con este enfoque:

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

Si más adelante encontrará la repetición de la misma parte del código a menudo, usted puede terminar con esto búsqueda en una función genérica, como esta:

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 

Aquí está un ejemplo de uso:

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

Se trabajará, suponiendo que tiene una clase similar declarada en el ámbito actual:

Class bar 
    Public Description As String 
End Class 

Por lo que el costo de la captura de excepciones, here is a link to my answer on a different question. Le da una idea de cómo atrapar la excepción afecta el rendimiento de depuración y la de su versión de lanzamiento. Semánticamente, es mejor evitar arrojar excepciones si se trata de una situación no excepcional, como ya se mencionó en otras respuestas.

Cuestiones relacionadas