practices - throw exception c#
Throwing ArgumentNullException (11)
1- Hazlo explícitamente si no quieres valor nulo. De lo contrario, cuando otra persona busque su código, ellos creerán que se acepta pasar un valor nulo.
2- Hazlo cuanto más rápido puedas. De esta forma, no se propaga el comportamiento "incorrecto" de tener un valor nulo cuando no se supone.
Supongamos que tengo un método que toma un objeto de algún tipo como argumento. Ahora diga que si a este método se le pasa un argumento nulo, es un error fatal y se debe lanzar una excepción. Me vale la pena codificar algo como esto (teniendo en cuenta que este es un ejemplo trivial):
void someMethod(SomeClass x)
{
if (x == null){
throw new ArgumentNullException("someMethod received a null argument!");
}
x.doSomething();
}
¿O es seguro para mí confiar solo en que arroje NullException cuando llama a x.doSomething ()?
En segundo lugar, supongamos que someMethod es un constructor y x no se usará hasta que se llame a otro método. ¿Debería lanzar la excepción inmediatamente o esperar hasta que se necesite x y arrojar la excepción, entonces?
Debería lanzar explícitamente una ArgumentNullException si espera que la entrada no sea nula. Es posible que desee escribir una clase llamada Guard que proporciona métodos de ayuda para esto. Entonces tu código será:
void someMethod(SomeClass x, SomeClass y)
{
Guard.NotNull(x,"x","someMethod received a null x argument!");
Guard.NotNull(y,"y","someMethod received a null y argument!");
x.doSomething();
y.doSomething();
}
El método NonNull haría la comprobación de nulidad y arrojaría una NullArgumentException con el mensaje de error especificado en la llamada.
Es mejor lanzar ArgumentNullException más temprano que tarde. Si lo arroja, puede proporcionar más información útil sobre el problema que una NullReferenceException.
Estoy de acuerdo con la idea de fallar rápido, sin embargo, es sabio saber por qué el fracaso rápido es práctico. Considera este ejemplo:
void someMethod(SomeClass x)
{
x.Property.doSomething();
}
Si confía en la NullReferenceException
para decirle que algo anda mal, ¿cómo sabrá lo que era nulo? La traza de la pila solo le dará un número de línea, no la referencia fue nula. En este ejemplo x
o x.Property
podría haber sido nulo y sin fallar rápidamente con una comprobación agresiva de antemano, no sabrá cuál es.
Prefiero la ArgumentNullException
sobre la NullReferenceException
que no proporcionaría la comprobación del argumento. En general, mi preferencia es verificar siempre la nulidad antes de intentar invocar un método en un objeto potencialmente nulo.
Si el método es un constructor, dependerá de un par de factores diferentes: ¿existe también un organismo público para la propiedad y qué tan probable es que el objeto se use realmente? Si hay un organismo público, entonces no proporcionar una instancia válida a través del constructor sería razonable y no debería dar lugar a una excepción.
Si no hay un organismo público y es posible utilizar el objeto que lo contiene sin referencia al objeto inyectado, es posible que desee aplazar la verificación / excepción hasta que se intente su uso. Sin embargo, creo que el caso general sería que el objeto inyectado es esencial para el funcionamiento de la instancia y, por lo tanto, una excepción ArgumentNull es perfectamente razonable ya que la instancia no puede funcionar sin ella.
Prefiero la excepción explícita, por estos motivos:
- Si el método tiene más de un argumento SomeClass, le da la oportunidad de decir cuál es (todo lo demás está disponible en la pila de llamadas).
- ¿Qué pasa si haces algo que pueda tener un efecto secundario antes de hacer referencia a x?
Prefiero la verificación de parámetros con la explícita ArgumentNullException, también.
Mirando los metadatos:
//
// Summary:
// Initializes a new instance of the System.ArgumentNullException class with
// the name of the parameter that causes this exception.
//
// Parameters:
// paramName:
// The name of the parameter that caused the exception.
public ArgumentNullException(string paramName);
Puede ver que la cadena debe ser el nombre del parámetro, que es nulo, y así darle al desarrollador una pista sobre lo que está pasando mal.
Probablemente voy a votar negativamente por esto, pero creo que es completamente diferente.
¿Qué hay de seguir una buena práctica llamada "nunca pasar nulo" y eliminar la fea comprobación de excepciones?
Si el parámetro es un objeto, NO PASE NULO. Además, NO DEVUELVA NULL. Incluso puede usar el patrón de objeto nulo para ayudar con eso.
Si es opcional, use valores predeterminados (si su idioma los admite) o cree una sobrecarga.
Mucho más limpio que desagradables excepciones.
Puede usar una sintaxis como la siguiente para no solo lanzar una ArgumentNullException
sino también tener ese nombre de excepción como parámetro de su texto de error. P.ej;
void SomeMethod(SomeObject someObject)
{
Throw.IfArgNull(() => someObject);
//... do more stuff
}
La clase utilizada para plantear la excepción es;
public static class Throw
{
public static void IfArgNull<T>(Expression<Func<T>> arg)
{
if (arg == null)
{
throw new ArgumentNullException(nameof(arg), "There is no expression with which to test the object''s value.");
}
// get the variable name of the argument
MemberExpression metaData = arg.Body as MemberExpression;
if (metaData == null)
{
throw new ArgumentException("Unable to retrieve the name of the object being tested.", nameof(arg));
}
// can the data type be null at all
string argName = metaData.Member.Name;
Type type = typeof(T);
if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
{
throw new ArgumentException("The expression does not specify a nullible type.", argName);
}
// get the value and check for null
if (arg.Compile()() == null)
{
throw new ArgumentNullException(argName);
}
}
}
Si programa a la defensiva, debe fallar rápidamente. Así que revisa tus entradas y error al principio de tu código. Debe ser amable con su interlocutor y darles el mensaje de error más descriptivo que pueda.
Siempre sigo la práctica de fallar rápido . Si su método depende de X y entiende que X podría pasarse en nulo, nírelo e inicie la excepción de inmediato en lugar de prolongar el punto de falla.
Actualización 2016:
Ejemplo del mundo real. Recomiendo encarecidamente el uso de anotaciones de Jetbrains .
[Pure]
public static object Call([NotNull] Type declaringType,
[NotNull] string methodName,
[CanBeNull] object instance)
{
if (declaringType == null) throw new ArgumentNullException(nameof(declaringType));
if (methodName == null) throw new ArgumentNullException(nameof(methodName));
Las declaraciones de Guard han sido ampliamente mejoradas con C # 6 proporcionando el nameof
operador.