c# design-by-contract

''Diseño por contrato'' en C#



design-by-contract (11)

Quería probar un pequeño diseño por contrato en mi última aplicación C # y quería tener una sintaxis similar a:

public string Foo() { set { Assert.IsNotNull(value); Assert.IsTrue(value.Contains("bar")); _foo = value; } }

Sé que puedo obtener métodos estáticos como este de un marco de prueba de unidades, pero quería saber si algo como esto ya estaba incorporado al lenguaje o si ya existía algún tipo de marco flotando. Puedo escribir mis propias funciones de Assert, simplemente no quiero reinventar la rueda.


Además de usar una biblioteca externa, tiene una afirmación simple en System.Diagnostics:

using System.Diagnostics Debug.Assert(value != null); Debug.Assert(value == true);

No es muy útil, lo sé.


Es posible que desee comprobar nVentive Umbrella :

using System; using nVentive.Umbrella.Validation; using nVentive.Umbrella.Extensions; namespace Namespace { public static class StringValidationExtensionPoint { public static string Contains(this ValidationExtensionPoint<string> vep, string value) { if (vep.ExtendedValue.IndexOf(value, StringComparison.InvariantCultureIgnoreCase) == -1) throw new ArgumentException(String.Format("Must contain ''{0}''.", value)); return vep.ExtendedValue; } } class Class { private string _foo; public string Foo { set { _foo = value.Validation() .NotNull("Foo") .Validation() .Contains("bar"); } } } }

Deseo que las extensiones de validación fueran constructores, por lo que podría hacer _foo = value.Validation().NotNull("Foo").Contains("bar").Value; pero es lo que es (afortunadamente su fuente abierta, por lo que es un constructor es un cambio trivial).

Y como una solución alternativa podría considerar la validación del dominio .

Finalmente, los nuevos lenguajes M , como parte de Oslo , admiten restricciones en sus extensiones y campos que se traducen tanto en validación de T-SQL como en clase CLR con pruebas de validación en funcionamiento (aunque Oslo tarda mucho tiempo en salir).






Para mi proyecto actual (febrero de 2010, VS 2008) elegí http://lightcontracts.codeplex.com/

Simple, solo es validación en tiempo de ejecución, sin complejidad extraña, no es necesario derivar de algunas clases base "extrañas", sin integración AOP, VS que no funcionará en algunas estaciones de trabajo de desarrollador, etc.

Simplicidad sobre complejidad.


C # 4.0 Contratos de código

Microsoft ha lanzado una biblioteca para diseño por contrato en la versión 4.0 del .NET Framework. Una de las mejores características de esa biblioteca es que también viene con herramientas de análisis estáticas (similares a FxCop, supongo) que aprovechan los detalles de los contratos que usted coloca en el código.

Aquí hay algunos recursos de Microsoft:

Aquí hay algunos otros recursos:


La manera más directa, y la manera utilizada en el .NET Framework mismo, es hacer:

public string Foo() { set { if (value == null) throw new ArgumentNullException("value"); if (!value.Contains("bar")) throw new ArgumentException(@"value should contain ""bar""", "value"); _foo = value; } }



Spec # es un popular proyecto de investigación de Microsoft que permite algunas construcciones DBC, como verificar las condiciones de publicación y pre. Por ejemplo, se puede implementar una búsqueda binaria con condiciones pre y post junto con invariantes de bucle. Este ejemplo y más:

public static int BinarySearch(int[]! a, int key) requires forall{int i in (0: a.Length), int j in (i: a.Length); a[i] <= a[j]}; ensures 0 <= result ==> a[result] == key; ensures result < 0 ==> forall{int i in (0: a.Length); a[i] != key}; { int low = 0; int high = a.Length - 1; while (low <= high) invariant high+1 <= a.Length; invariant forall{int i in (0: low); a[i] != key}; invariant forall{int i in (high+1: a.Length); a[i] != key}; { int mid = (low + high) / 2; int midVal = a[mid]; if (midVal < key) { low = mid + 1; } else if (key < midVal) { high = mid - 1; } else { return mid; // key found } } return -(low + 1); // key not found. }

Tenga en cuenta que el uso del lenguaje Spec # da como resultado la verificación del tiempo de compilación para las construcciones DBC, que para mí es la mejor forma de aprovechar DBC. A menudo, confiar en las afirmaciones de tiempo de ejecución se convierte en un dolor de cabeza en la producción y, en general, las personas eligen usar excepciones .

Hay otros lenguajes que adoptan conceptos DBC como construcciones de primera clase, concretamente Eiffel, que también está disponible para la plataforma .NET.