En C #, ¿hay alguna buena razón (aparte de un mejor mensaje de error) para agregar verificaciones nulas de parámetros a cada función donde nulo no es un valor válido? Obviamente, el código que usa s lanzará una excepción de todos modos. Y tales comprobaciones hacen que el código sea más lento y difícil de mantener.
void f(SomeType s)
{
if (s == null)
{
throw new ArgumentNullException("s cannot be null.");
}
// Use s
}
Respuestas:
Sí, hay buenas razones:
NullReferenceException
Ahora en cuanto a sus objeciones:
Y para tu afirmación:
De Verdad? Considerar:
void f(SomeType s) { // Use s Console.WriteLine("I've got a message of {0}", s); }
Eso usa
s
, pero no lanza una excepción. Si no es válido paras
ser nulo, y eso indica que algo anda mal, una excepción es el comportamiento más apropiado aquí.Ahora, dónde colocas esas comprobaciones de validación de argumentos es un asunto diferente. Puede decidir confiar en todo el código dentro de su propia clase, así que no se preocupe por los métodos privados. Puede decidir confiar en el resto de su ensamblaje, así que no se preocupe por los métodos internos. Es casi seguro que debería validar los argumentos de los métodos públicos.
Una nota al margen: la sobrecarga del constructor de un solo parámetro de
ArgumentNullException
debería ser solo el nombre del parámetro, por lo que su prueba debería ser:if (s == null) { throw new ArgumentNullException("s"); }
Alternativamente, puede crear un método de extensión, permitiendo algo más terso:
s.ThrowIfNull("s");
En mi versión del método de extensión (genérico), hago que devuelva el valor original si no es nulo, lo que le permite escribir cosas como:
this.name = name.ThrowIfNull("name");
También puede tener una sobrecarga que no toma el nombre del parámetro, si no le preocupa demasiado.
fuente
ThrowIfEmpty
elICollection
Debug.Assert
. Es incluso más importante detectar errores en la producción (antes de que estropeen los datos reales) que en el desarrollo.throw new ArgumentNullException(nameof(s))
Estoy de acuerdo con Jon, pero agregaría una cosa a eso.
Mi actitud sobre cuándo agregar comprobaciones nulas explícitas se basa en estas premisas:
throw
las declaraciones son declaraciones .if
es una declaración .throw
enif (x == null) throw whatever;
Si no hay forma posible de ejecutar esa declaración, no se puede probar y se debe reemplazar por
Debug.Assert(x != null);
.Si hay una forma posible de ejecutar esa declaración, escriba la declaración y luego escriba una prueba unitaria que la ejercite.
Es particularmente importante que los métodos públicos de tipo público verifiquen sus argumentos de esta manera; no tienes idea de la locura que van a hacer tus usuarios. Dales el "oye, idiota, ¡lo estás haciendo mal!" excepción tan pronto como sea posible.
Por el contrario, es mucho más probable que los métodos privados de tipos privados se encuentren en una situación en la que controle los argumentos y pueda tener una fuerte garantía de que el argumento nunca sea nulo; use una afirmación para documentar ese invariante.
fuente
He estado usando esto durante un año:
_ = s ?? throw new ArgumentNullException(nameof(s));
Es un delineador único y el descarte (
_
) significa que no hay asignación innecesaria.fuente
Sin una
if
verificación explícita , puede ser muy difícil averiguar qué fuenull
si no posee el código.Si obtiene una información
NullReferenceException
de lo más profundo de una biblioteca sin código fuente, es probable que tenga muchos problemas para averiguar qué hizo mal.Estas
if
comprobaciones no harán que su código sea notablemente más lento.Tenga en cuenta que el parámetro del
ArgumentNullException
constructor es un nombre de parámetro, no un mensaje.Tu código debe ser
if (s == null) throw new ArgumentNullException("s");
Escribí un fragmento de código para facilitar esto:
<?xml version="1.0" encoding="utf-8" ?> <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0"> <Header> <Title>Check for null arguments</Title> <Shortcut>tna</Shortcut> <Description>Code snippet for throw new ArgumentNullException</Description> <Author>SLaks</Author> <SnippetTypes> <SnippetType>Expansion</SnippetType> <SnippetType>SurroundsWith</SnippetType> </SnippetTypes> </Header> <Snippet> <Declarations> <Literal> <ID>Parameter</ID> <ToolTip>Paremeter to check for null</ToolTip> <Default>value</Default> </Literal> </Declarations> <Code Language="csharp"><![CDATA[if ($Parameter$ == null) throw new ArgumentNullException("$Parameter$"); $end$]]> </Code> </Snippet> </CodeSnippet> </CodeSnippets>
fuente
Es posible que desee echar un vistazo a los contratos de código si necesita una forma más agradable de asegurarse de no obtener ningún objeto nulo como parámetro.
fuente
El principal beneficio es que está siendo explícito con los requisitos de su método desde el principio. Esto deja en claro a otros desarrolladores que trabajan en el código que es realmente un error que una persona que llama envíe un valor nulo a su método.
La verificación también detendrá la ejecución del método antes de que se ejecute cualquier otro código. Eso significa que no tendrá que preocuparse por las modificaciones que se realizan con el método que quedan sin terminar.
fuente
Ahorra algo de depuración, cuando golpea esa excepción.
La excepción ArgumentNullException indica explícitamente que era "s" la que era nula.
Si no tiene esa verificación y deja que el código explote, obtendrá una NullReferenceException de alguna línea no identificada en ese método. ¡En una versión de lanzamiento no obtienes números de línea!
fuente
Codigo original:
void f(SomeType s) { if (s == null) { throw new ArgumentNullException("s cannot be null."); } // Use s }
Reescribirlo como:
void f(SomeType s) { if (s == null) throw new ArgumentNullException(nameof(s)); }
[Editar] La razón para reescribir el uso
nameof
es porque permite una refactorización más fácil. Si el nombre de su variables
alguna vez cambia, los mensajes de depuración también se actualizarán, mientras que si solo codifica el nombre de la variable, eventualmente quedará desactualizado cuando se realicen actualizaciones con el tiempo. Es una buena práctica utilizada en la industria.fuente
int i = Age ?? 0;
Entonces, para tu ejemplo:
if (age == null || age == 0)
O:
if (age.GetValueOrDefault(0) == 0)
O:
if ((age ?? 0) == 0)
O ternario:
int i = age.HasValue ? age.Value : 0;
fuente