''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).
Al revisar el código de Moq, vi que usan una clase llamada ''Guard'' que proporciona métodos estáticos para verificar las condiciones previas y posteriores . Pensé que era limpio y muy claro. Expresa lo que estaría pensando al implementar el diseño mediante verificaciones contractuales en mi código.
p.ej
public void Foo(Bar param)
{
Guard.ArgumentNotNull(param);
}
Pensé que era una forma ordenada de expresar el diseño mediante comprobaciones contractuales.
Puede utilizar una implementación de diseño por contrato desde una arquitectura nítida. Aquí está el enlace: http://code.google.com/p/sharp-architecture/
Saludos,
Liang
Pruebe la Biblioteca DesignByContract de LinFu:
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:
- El sitio principal de Microsoft Research
- El manual del usuario
- La presentación del PDC 2008
- La presentación del PDC 2009
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;
}
}
Tiene una respuesta en .net Fx 4.0:
System.Diagnostics.Contracts
http://msdn.microsoft.com/en-us/library/dd264808.aspx
Contract.Requires(newNumber > 0, “Failed contract: negative”);
Contract.Ensures(list.Count == Contract.OldValue(list.Count) + 1);
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.