2010-12-15 13 views
17

De la parte superior de mi cabeza, no puedo pensar en 4 formas de comprobar los argumentos nulos:Pros/contras de diferentes métodos para probar las condiciones previas?

Debug.Assert(context != null); 
Contract.Assert(context != null); 
Contract.Requires(context != null); 
if (context == null) throw new ArgumentNullException("context"); 

Siempre he usado el último método, pero acabo de ver un fragmento de código que utiliza Contract.Requires, que me estoy familiarizado con ¿Cuáles son las ventajas/desventajas de cada método? ¿Hay otras formas?


En VS2010 w/ReSharper,

  • Contract.Assert me advierte que la expresión es siempre cierto (como se sabe, no estoy muy seguro ... no puede ser nula HttpContext?),
  • Contract.Requires consigue desvaneció y me dice que el compilador no invocará el método (supongo que debido a la razón anterior, que nunca será nulo) y
  • si cambio de último recurso para todos context != null el código siguiente el ala se desvanece y me dice que el código es heurísticamente inalcanzable.

Por lo tanto, parece que los últimos 3 métodos tienen algún tipo de inteligencia integrada en el comprobador estático VS, y Debug.Assert es tonto.

+0

La pregunta no está clara. ¿Estás tratando de usarlos todos a la vez? –

+0

@Matthew: No estoy seguro de cómo no está claro ... no, no estoy tratando de usarlos todos a la vez. Hice un fragmento de código así solo para ilustrar las diferentes formas en que puede verificar null. – mpen

+0

Eso es lo que pensé del resto de la pregunta, pero la presentación de sintaxis que usaste fue extraña. –

Respuesta

12

Supongo que hay un contrato aplicado a la interfaz IHttpHandler.ProcessRequest que requiere ese contexto! = Null. Los contratos de interfaz son heredados por sus implementadores, por lo que no necesita repetir el Requiere. De hecho, no tiene permitido agregar instrucciones adicionales de Requiere, ya que está limitado a los requisitos asociados con el contrato de interfaz.

Creo que es importante hacer una distinción entre especificar una obligación contractual versus simplemente realizar una verificación nula. Puede implementar una comprobación nula y lanzar una excepción en el tiempo de ejecución, como una forma de informar al desarrollador que están usando su API correctamente. Una expresión de contrato, por otro lado, es realmente una forma de metadatos, que puede ser interpretada por el reescritor de contrato (para introducir las excepciones de tiempo de ejecución que se implementaron previamente manualmente), pero también por el analizador estático, que puede usarlos para razonar sobre la corrección estática de su aplicación.

Dicho esto, si trabaja en un entorno en el que utiliza activamente contratos de código y análisis estático, entonces es preferible colocar las afirmaciones en forma de contrato para aprovechar el análisis estático. Incluso si no está utilizando el análisis estático, aún puede dejar la puerta abierta para beneficios posteriores mediante el uso de contratos. Lo principal a tener en cuenta es si ha configurado sus proyectos para realizar la reescritura, ya que de lo contrario los contratos no darán como resultado excepciones de tiempo de ejecución como podría esperar.


dar más detalles sobre lo que los comentaristas han dicho, la diferencia entre Assert, asumir y que requiere es:

    expresión
  • Un Contract.Assert se transforma en una afirmación por la re-escritura del contrato y el analizador estático intenta probar la expresión en base a su evidencia existente. Si no puede ser probado, recibirá una advertencia de análisis estático.
  • A Contract.Assume expression es ignorada por el reescritor de contrato (hasta donde yo sé), pero es interpretada por el analizador estático como una nueva evidencia que puede tener en cuenta en su análisis estático. Contrato.Asumir se usa para "llenar las lagunas" en el análisis estático, ya sea que carece de la sofisticación para realizar las inferencias necesarias o cuando se interopera con un código que no ha sido decorado con Contratos, por lo que se puede Suponer, por ejemplo, que una llamada de función particular devuelve un resultado no nulo.
  • Contract.Requires son condiciones que siempre deben cumplirse cuando se llama a su método. Pueden ser restricciones en los parámetros del método (que son los más típicos) y también pueden ser restricciones en los estados públicamente visibles del objeto (por ejemplo, puede permitir que solo se llame al método si Initialized es True.) Estos tipos de restricciones empujan a los usuarios de su clase a comprobar Inicializado cuando usan el objeto (y presumiblemente manejan el error apropiadamente si no es así) o crean sus propias restricciones y/o invariantes de clase para aclarar que la Inicialización, de hecho, sucedió.
+0

Entonces ... ¿cuál es exactamente la diferencia entre 'Contract.Assert' y' Contract.Requires' entonces? – mpen

+2

@Ralph: 'Contract.Requires' indica cosas que deberían ser verdaderas cuando se llama al método,' Contract.Assert' debe ir en el medio de su método para verificar los estados intermedios. Agregar 'Contract.Assert's en los lugares correctos puede ayudar al analizador estático a probar que su código es correcto si no puede administrarlo por sí mismo. –

+3

En realidad, el verificador estático solo se beneficiaría de Contract.Assume. Este método se comporta como Contract.Assert en tiempo de ejecución, pero le dice al verificador estático que no intente probarlo estadísticamente. – koenmetsu

2

El primer método es apropiado para probar una condición nula que nunca debería existir. Es decir, úselo durante el desarrollo para asegurarse de que no se configure inesperadamente como nulo. Dado que no maneja ningún error, esto no es apropiado para manejar condiciones nulas en su producto lanzado.

Diría que las versiones segunda y tercera son similares en cuanto a que no manejan el problema de ninguna manera.

En general, si existe la posibilidad de que la variable en realidad sea nula en el producto final, la última versión es la que se utilizará. Podría hacer un manejo especial allí o simplemente hacer una excepción como lo hizo.

+1

En realidad, los métodos 2º y 3º usan análisis estáticos para intentar probar que son verdaderos en tiempo de compilación. –

+0

@Anon: Pero el analizador estático no podrá detectar todas las excepciones nulas en tiempo de compilación ... ¿qué ocurre si se pasa? ¿Lanza una excepción, falla, no hace nada o qué? – mpen

+1

@Ralph: si el analizador estático no puede probar algo de alguna manera (no puede mostrar que el contrato fallará en algunos casos, pero tampoco puede probar que siempre sea correcto), mostrará una advertencia de compilación (no una error) y reemplazarlo con una aserción. –

Cuestiones relacionadas