.net - question - ¿Dónde comprobar si un objeto es nulo o no?
isnull c# (12)
¿Qué querrías hacer si la instancia es nula?
Creo que depende de la API que proporcione y defina el contrato (la forma en que lo hacen las clases de .net framework). Dicho esto, no es necesario realizar una comprobación de nulo (en main), si el método define el resultado esperado en caso de que se le pase una referencia nula.
¿Dónde verifica si un objeto que está pasando a un método es nulo o no?
¿Debería probarse un objeto antes de llamar a un método? ¿O dentro del método que está utilizando el argumento?
public class Program
{
public static void Main(string[] args)
{
// Check if person is null here? or within PrintAge?
PrintAge(new Person { Age = 1 });
}
private static void PrintAge(Person person)
{
// check if person is null here?
Console.WriteLine("Age = {0}", person.Age);
}
}
public class Person
{
public int Age { get; set; }
}
Tener una comprobación "nula" en ambas clases parece ser un código demasiado redundante.
[EDITAR] : ¿Qué sería una desventaja de la comprobación de nulo dentro de una persona que llama o una persona llamada?
[EDIT2] : Me acabo de encontrar con programación defensiva y parece que aboga por la verificación de nulo dentro de una persona llamada. Me pregunto si esta es una práctica ampliamente aceptada.
¿Quieres decir revisar ambos métodos? Lo comprobaría en PrintAge con seguridad y si también tiene sentido dentro de Main. No creo que haya una respuesta definitiva en general. Depende :-)
Como entiendo su pregunta, es más general de lo que ilustra su ejemplo. Mis preferencias son las siguientes:
- Todos los métodos de acceso público deben verificar la entrada NULA y lanzar excepciones según corresponda. Entonces, si estás construyendo un marco para que otros lo usen, codifica defensivamente.
- Los métodos privados pueden omitir la comprobación NULA si sabe que esto se hace en otro lugar o que los argumentos nunca serán NULOS, pero en general prefiero la excepción ArgumentNullException explícita a NullRefereceException.
Brad Abrams tiene más información aquí: http://blogs.msdn.com/brada/archive/2004/07/11/180315.aspx
Definitivamente verifique en PrintAge
, es un lugar correcto para verificar. Puede ser redundante pero no lastimará a nadie a menos que lo ejecutes 1000 veces por segundo. (Dependiendo del cheque, lance una excepción o corríjala si puede)
La otra verificación depende de su flujo real, en este ejemplo no tiene un flujo, así que no puedo comentar sobre ese bit. Pero generalmente considera tus parámetros como contaminados.
El código redundante no es el más elegante, pero es seguro.
Esto depende de quién es su usuario previsto, si usted es quien tiene el control de cómo se usa todo y las verificaciones solo son necesarias si no está seguro de cuál será el estado de sus variables.
Si está haciendo esto para que lo use otra persona, entonces los cheques nulos son probablemente una buena idea. Incluso si acaba de lanzar una NullPointerException, es mejor fallar rápidamente.
No tiene nada que verificar en Main
: está utilizando el new
operador que nunca devuelve nulo (excepto para Nullable<T>
).
Sería completamente razonable revisar PrintAge
, especialmente si se hiciera público. (Para las API privadas, es menos importante hacer la comprobación de argumentos, pero aún puede ser muy útil).
if (person == null)
{
throw new ArgumentNullException("person");
}
Estos días en C # 3.0 usualmente uso un método de extensión para esto .
Normalmente permito que mis cheques nulos sean controlados por mis expectativas; Si espero que algo sea nulo o no estoy seguro de ello, agrego un cheque. De lo contrario no lo hago. Las excepciones de Nulllpointer se encuentran entre los problemas más fáciles de rastrear, por lo que la cantidad excesiva de cheques aumenta el código. En el ejemplo específico, no verificaría nada, porque es intuitivo y no es nulo.
PrintAge debe ser un método en persona, no un estático tomando una persona como parámetro. No es necesario comprobar.
La comprobación de valores nulos hace que el código sea innecesariamente complejo. Estructure su código para limitar (o eliminar) las ocasiones en que el valor nulo es un valor posible, y tendrá mucho menos cheques que escribir.
Puede diseñar un método para trabajar solo con objetos válidos.
Eso significa que espera recibir objetos válidos (no nulos en su caso).
Eso significa que no sabes cómo reaccionar y qué hacer con objetos no válidos:
- regresar silenciosamente de la función no es una solución;
- lanzar una excepción significará que mueves la responsabilidad a los métodos superiores donde pueden verificar el valor antes de pasarte a ti.
Entonces, si su método no sabe exactamente cómo manejar un objeto no válido y el método no seguirá una lógica adicional en el caso no válido, debe poner
Debug.Assert( Person );
en el inicio de PrintAge
y esto te obligará a hacer cheques en la parte superior por pila de llamadas.
La función inferior en la jerarquía es la menor cantidad de controles que debería hacer . Las siguientes son las desventajas de hacer verificaciones en las funciones que hacen el trabajo.
- La función que realiza el trabajo real debe ser lo más clara posible sin una masa de si s
- La función será llamada más de una vez
- Dicha función puede llamar a tales funciones y puede volver a llamar tales funciones. Cada uno de ellos realizará la misma validación.
Si diseñas una biblioteca, habrá métodos expuestos al mundo exterior. Debe comprobar los datos entrantes en estos métodos. No se requieren comprobaciones en los métodos que no expone, porque solo su código los llama y su lógica debe manejar todos los casos que aceptó en el método expuesto.
--------------------------
| |
| Library |
| |
------- --------- ---------- |
| | | | | | |
| Outer | | Library | | Library | |
| | ===> | Entry | ===> | Backend/ | |
| World | | Method | | Helpers | |
| | | | | | |
------- --------- ---------- |
| |
| |
--------------------------
Si ha aceptado los datos proporcionados en el método de entrada, debe realizar la acción solicitada y devolver el resultado esperado, es decir, manejar todos los casos restantes.
ACTUALIZAR
Para aclarar la situación dentro de la biblioteca. Puede haber comprobaciones nulas, pero solo por la lógica, no por la validación de parámetros. Hay dos posibilidades para la ubicación de cheques nulos dentro de la biblioteca. El primero si el método llamado sabe cómo manejar valores nulos.
private CallingMethod()
{
CalledMethod(someData);
}
private CalledMethod(Object parameter)
{
if (parameter == null)
{
// Do something
}
else
{
// Do something else
}
}
Y la segunda situación si llama a un método que no puede manejar valores nulos.
private CallingMethod()
{
if (someData == null)
{
// Do the work myself or call another method
}
else
{
CalledMethod(someData);
}
}
private CalledMethod(Object parameter)
{
// Do something
}
La idea general es rechazar los casos que no puede manejar de manera inmediata y manejar todos los casos restantes correctamente. Si la entrada no es válida lanza una excepción. Esto obliga a la persona que llama a la biblioteca a proporcionar solo valores válidos y no permite que la persona que llama continúe la ejecución con valores de retorno sin sentido (además de la persona que llama, la excepción continúa).
Solo hay una ocasión en la que un constructor puede devolver nulo [ new()
en un Nullable<T>
], por lo que no es necesario verificar el código de llamada.
La persona que llama probablemente debería verificar; lanzando una ArgumentNullException
si era nulo. En .NET 4.0 esto será mejor atendido por los contratos de código. Pero no todavía ;-p
Yo diría que revisarlo n PrintAge parece tener más sentido ya que eso está cumpliendo con el contrato de la rutina. Por supuesto, podría reemplazar los cheques nulos con el código Debug.Assert () para verificar en el momento de la prueba, pero no en el tiempo de lanzamiento.