c# - for - Cómo utilizar correctamente los contratos de código en.NET Core
tag helpers asp net core 2 (1)
En primer lugar, entendamos qué son los CodeContracts , de acuerdo con los documentos de Microsoft :
Los contratos de código proporcionan una manera de especificar condiciones previas, condiciones posteriores e invariantes de objetos en su código. Las condiciones previas son requisitos que deben cumplirse al ingresar un método o propiedad. Las condiciones posteriores describen las expectativas en el momento en que sale el método o el código de propiedad. Los invariantes de objetos describen el estado esperado para una clase que se encuentra en buen estado.
Es decir, para simplificar las cosas, los CodeContracts nos ayudan a simplificar las pruebas en nuestro código.
¿Cómo utilizamos los contratos de código?
Considera este ejemplo:
if ( x == null ) throw new ...
Contract.EndContractBlock(); // All previous "if" checks are preconditions
¿Qué significa por condiciones previas uno de dos casos?
- Las declaraciones aparecen antes que cualquier otra declaración en un método.
- El conjunto completo de dichas declaraciones va seguido de una llamada de método de Contract explícita, como una llamada al método de EndContractBlock , EnsuresOnThrow , EndContractBlock o EndContractBlock .
Cuando las declaraciones if-then-throw
aparecen en esta forma, las herramientas las reconocen como legadas y requieren declaraciones. Si no hay otros contratos que sigan la secuencia if-then-throw, finalice el código con el método EndContractBlock .
Puedes usarlo también en Postcondiciones :
¿Qué son las postcondiciones ?
Las postcondiciones son contratos para el estado de un método cuando termina. La condición posterior se verifica justo antes de salir de un método. El comportamiento en tiempo de ejecución de las postcondiciones fallidas está determinado por el analizador de tiempo de ejecución.
A diferencia de las condiciones previas, las condiciones posteriores pueden hacer referencia a los miembros con menos visibilidad. Es posible que un cliente no pueda entender o hacer uso de parte de la información expresada por una condición posterior que utiliza el estado privado, pero esto no afecta la capacidad del cliente para usar el método correctamente.
Es decir, para abreviar, las condiciones posteriores nos ayudan a probar nuestros métodos.
un ejemplo sería:
Contract.Ensures( this.F > 0 );
Por favor tenga en cuenta postcontions especiales:
- Puede hacer referencia a los valores de retorno del método en condiciones posteriores utilizando la expresión
Contract.Result<T>()
, dondeT
se reemplaza por el tipo de retorno del método. Cuando el compilador no puede inferir el tipo, debe proporcionarlo explícitamente. - Un valor de pre-estado en una post-condición se refiere al valor de una expresión al inicio de un método o propiedad. Utiliza la expresión
Contract.OldValue<T>(e)
, dondeT
es el tipo dee
. Puede omitir el argumento de tipo genérico siempre que el compilador pueda inferir su tipo. (Por ejemplo, el compilador de C # siempre infiere el tipo porque toma un argumento). Hay varias restricciones sobre lo que puede ocurrir en e y los contextos en los que puede aparecer una expresión antigua. Una expresión antigua no puede contener otra expresión antigua. Lo más importante es que una expresión antigua debe referirse a un valor que existía en el estado de condición previa del método. En otras palabras, debe ser una expresión que se pueda evaluar siempre que la condición previa del método sea verdadera.
Finalmente tienes Invariantes:
Las invariantes de objetos son condiciones que deben cumplirse para cada instancia de una clase siempre que ese objeto sea visible para un cliente. Expresan las condiciones bajo las cuales el objeto se considera correcto.
Es decir, los invariantes ayudan a probar nuestro código de clase e instancias.
Un ejemplo sería:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant(this.y >= 0);
Contract.Invariant(this.x > this.y);
...
}
Ejemplo completo para el uso adecuado de CodeContracts :
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Http.Headers;
using System.Diagnostics.Contracts;
namespace System.Net.Http
{
public class FormUrlEncodedContent : ByteArrayContent
{
public FormUrlEncodedContent(IEnumerable<KeyValuePair<string, string>> nameValueCollection)
: base(GetContentByteArray(nameValueCollection))
{
Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
}
private static byte[] GetContentByteArray(IEnumerable<KeyValuePair<string, string>> nameValueCollection)
{
if (nameValueCollection == null)
{
throw new ArgumentNullException(nameof(nameValueCollection));
}
Contract.EndContractBlock();
// Encode and concatenate data
StringBuilder builder = new StringBuilder();
foreach (KeyValuePair<string, string> pair in nameValueCollection)
{
if (builder.Length > 0)
{
builder.Append(''&'');
}
builder.Append(Encode(pair.Key));
builder.Append(''='');
builder.Append(Encode(pair.Value));
}
return HttpRuleParser.DefaultHttpEncoding.GetBytes(builder.ToString());
}
private static string Encode(string data)
{
if (String.IsNullOrEmpty(data))
{
return String.Empty;
}
// Escape spaces as ''+''.
return Uri.EscapeDataString(data).Replace("%20", "+");
}
internal override Stream TryCreateContentReadStream() =>
GetType() == typeof(FormUrlEncodedContent) ? CreateMemoryStreamForByteArray() : // type check ensures we use possible derived type''s CreateContentReadStreamAsync override
null;
}
}
Me pregunto cómo usar adecuadamente los Contratos de Código en .NET Core , hasta ahora intenté agregar CC a mi proyecto, compilar y depurar. Estoy confundido por el mensaje, que aparece en cada llamada que utiliza Contract.Requires
. Requisitos, e información encontrada en Google.
El mensaje dice:
Un ensamblaje debe reescribirse utilizando el código de los reescritores binarios (CCRewrite) porque está llamando a
Contract.Requires<TException>
y se define el símboloCONTRACTS_FULL
. Elimine cualquier definición explícita del símboloCONTRACTS_FULL
de su proyecto y reconstrúyala. CCRewrite ....
Como puedo ver, no hay opciones de CC en las propiedades del proyecto y como puedo ver, el repositorio Github de CC está casi muerto. ¿Hay alguna manera de cómo usar CC correctamente en .NET Core?
Y si no, ¿hay alguna forma sencilla de cómo reemplazarlos? Yo uso Contract.Requires
y ContractClassAttribute
. Reemplazar Contract.Requires
es obvio, pero ContractClassAttribute me sorprende :-)