Soy un gran fanático de escribir afirmaciones, contratos o cualquier tipo de cheques disponibles en el idioma que estoy usando. Una cosa que me molesta un poco es que no estoy seguro de cuál es la práctica común para hacer frente a los controles duplicados.
Situación de ejemplo: primero escribo la siguiente función
void DoSomething( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
//code using obj
}
luego, unas horas más tarde, escribo otra función que llama a la primera. Como todo está fresco en la memoria, decido no duplicar el contrato, ya que sé que ya DoSomething
comprobará si hay un objeto nulo:
void DoSomethingElse( object obj )
{
//no Requires here: DoSomething will do that already
DoSomething( obj );
//code using obj
}
El problema obvio: DoSomethingElse
ahora depende DoSomething
de verificar que obj no sea nulo. Por lo tanto, debería DoSomething
decidir no verificar más, o si decido usar otra función, obj podría no verificarse más. Lo que me lleva a escribir esta implementación después de todo:
void DoSomethingElse( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
DoSomething( obj );
//code using obj
}
Siempre seguro, no se preocupe, excepto que si la situación crece, el mismo objeto podría verificarse varias veces y es una forma de duplicación y todos sabemos que eso no es tan bueno.
¿Cuál es la práctica más común para situaciones como estas?
fuente
ArgumentBullException
? Esa es una nueva :)Respuestas:
Personalmente, verificaría si hay nulo en cualquier función que fallará si se obtiene un nulo, y no en ninguna función que no lo haga.
Entonces, en su ejemplo anterior, si doSomethingElse () no necesita desreferenciar obj, entonces no comprobaría obj para nulo allí.
Si DoSomething () no hace referencia a obj, entonces debería verificar nulo.
Si ambas funciones lo desreferencian, ambos deberían verificar. Entonces, si DoSomethingElse desreferencia obj, entonces debería verificar si es nulo, pero DoSomething también debería verificar si es nulo, ya que puede llamarse desde otra ruta.
De esta manera, puede dejar el código bastante limpio y aún así garantizar que los cheques estén en el lugar correcto.
fuente
DoSomething()
tal que la condición previa ya no sea necesaria (poco probable en este caso particular, pero podría suceder en una situación diferente), y elimine la verificación de la condición previa. Ahora, algún método aparentemente no relacionado está roto debido a la condición previa que falta. Tomaré un poco de duplicación de código para aclarar sobre fallas extrañas como esa por el deseo de guardar algunas líneas de código, cualquier día.¡Excelente! Veo que te enteraste de los contratos de código para .NET. Code Contracts va mucho más allá de sus afirmaciones promedio, de las cuales el verificador estático es el mejor ejemplo. Es posible que esto no esté disponible para usted si no tiene instalado Visual Studio Premium o superior, pero es importante comprender la intención detrás de esto si va a usar contratos de código.
Cuando aplica un contrato a una función, literalmente es un contrato . Esa función garantiza comportarse de acuerdo con el contrato y se garantiza que solo se utilizará según lo definido por el contrato.
En su ejemplo dado, la
DoSomethingElse()
función no cumple con el contrato según lo especificado porDoSomething()
, ya que se puede pasar nulo, y el verificador estático indicará este problema. La forma de resolver esto es agregando el mismo contrato aDoSomethingElse()
.Ahora, esto significa que habrá duplicación, pero esta duplicación es necesaria ya que elige exponer la funcionalidad en dos funciones. Estas funciones, aunque privadas, también se pueden invocar desde diferentes lugares de su clase, por lo que la única forma de garantizar que de una llamada dada el argumento nunca sea nulo es duplicar los contratos.
Esto debería hacer que reconsidere por qué divide el comportamiento en dos funciones en primer lugar. Siempre ha sido mi opinión ( contrario a la creencia popular ) que no debe dividir funciones que solo se llaman desde un solo lugar . Al exponer la encapsulación aplicando los contratos, esto se vuelve aún más evidente. ¡Parece que encontré una argumentación adicional para mi causa! ¡Gracias! :)
fuente