.net-4.0 code-contracts

.net 4.0 - Contratos de código-Suponer vs Requiere



.net-4.0 code-contracts (3)

Solo difiere tiempo de diseño / tiempo de análisis estático

Contrato.Asumir: "Indica a las herramientas de análisis de código que asuman que la condición especificada es verdadera, incluso si no se puede demostrar estáticamente que siempre es verdadera" Y: En tiempo de ejecución, usar este método equivale a usar el método Assert (Boolean).

Contract.Requires garantizará que el predicado dado sea verdadero y los analizadores de código estáticos puedan generar un error si no pueden ''probar'' que ese no es el caso. En contrato. Supongamos que el analizador estático continuará / emitirá una advertencia / lo que sea que la herramienta decida.

¿Cuál es la diferencia entre estas dos afirmaciones?

Contract.Requires(string.IsNullOrWhiteSpace(userName)); Contract.Assume(string.IsNullOrWhiteSpace(userName));


Imagina que tienes un método como este:

bool ContainsAnX(string s) { return s.Contains("X"); }

Ahora, este método siempre fallará si le pasa null , por lo que desea asegurarse de que esto nunca suceda. Esto es para lo que Contract.Requires es. Establece una condición previa para el método, que debe ser verdadera para que el método se ejecute correctamente. En este caso, tendríamos:

bool ContainsAnX(string s) { Contract.Requires(s != null); return s.Contains("X"); }

( Nota : Requires y Ensures siempre debe estar al inicio de un método, ya que son información sobre el método como un todo. Assume se utiliza en el código en sí, ya que es información sobre ese punto en el código).

Ahora, en su código que llama al método "ContainsAnX", debe asegurarse de que la cadena no sea nula. Tu método podría verse así:

void DoSomething() { var example = "hello world"; if (ContainsAnX(example)) Console.WriteLine("The string contains an ''X''."); else Console.WriteLine("The string does not contain an ''X''."); }

Esto funcionará bien, y el verificador estático puede demostrar que el example no es nulo.

Sin embargo, es posible que llame a bibliotecas externas, que no tienen información sobre los valores que devuelven (es decir, no usan Contratos de código). Cambiemos el ejemplo:

void DoSomething() { var example = OtherLibrary.FetchString(); if (ContainsAnX(example)) Console.WriteLine("The string contains an ''X''."); else Console.WriteLine("The string does not contain an ''X''."); }

Si la OtherLibrary no utiliza Contratos de Código, el verificador estático se quejará de que el example podría ser nulo.

Tal vez su documentación para la biblioteca dice que el método nunca volverá nulo (¡o nunca debería ser!). En este caso, sabemos más que el verificador estático, por lo que podemos decir que Assume que la variable nunca será nula:

void DoSomething() { var example = OtherLibrary.FetchString(); Contract.Assume(example != null); if (ContainsAnX(example)) Console.WriteLine("The string contains an ''X''."); else Console.WriteLine("The string does not contain an ''X''."); }

Ahora esto estará bien con el verificador estático. Si tiene contratos de tiempo de ejecución habilitados, Assume también se comprobará en tiempo de ejecución.

Otro caso en el que podría necesitar Asumir es cuando sus condiciones previas son muy complejas y el verificador estático está teniendo dificultades para probarlas. En este caso, puedes darle un empujoncito para que lo ayude :)

En términos de comportamiento en el tiempo de ejecución, no habrá mucha diferencia entre usar Asumir y Requiere. Sin embargo, los resultados con el verificador estático serán muy diferentes. El significado de cada uno es diferente también, en términos de quién es responsable del error en caso de falla:

  • Requiere significa que el código que llama a este método debe garantizar que la condición se mantenga.
  • Suponer significa que este método está haciendo una suposición que siempre debería ser cierta.

De acuerdo con la documentación oficial : páginas 7 (precondiciones) y 11 (se supone).

Requiere:

  • Es una condición previa ("las condiciones previas se eliminan mediante el uso de Contract.Requires");
  • Como una condición previa se ejecutará en el método de invocación;

Asume:

  • No es una condición previa, ni una condición posterior, ni un invariante;
  • Se ejecuta en el punto donde está especificado;
  • pag. 11 "Existe en una compilación solo cuando se define el símbolo de contrato completo o el símbolo DEBUG";