martes, 26 de julio de 2011

Contratos en C#. Parte 1.

En nuestro libro Algoritmos Objetos y Estructuras de Datos los algoritmos y ejemplos están realizados en C# y Eiffel.
Eiffel tiene el soporte nativo para contratos de software, es el lenguaje pionero en ese sentido. Pero también es posible realizar contratos en C# y en cualquier lenguaje sobre .NET usando  Microsoft Code Contracts.
Code Contracts provee un manera independiente del lenguaje de expresar precondiciones, poscondiciones e invariantes.  Hay algunas diferencias con los contratos en Eiffel fundamentalmente en el tema de la herencia pero igualmente son una poderosa herramienta de construcción de software confiable. Además de la librería hay una serie de herramientas que permiten la verificación de contratos:

  • ccrewrite: permite generar chequeos en tiempo de ejecución para los contratos
  • cccheck un verificador estático de contratos en tiempo de compilación
  • ccdoc que permite agregar los contratos a los archivos de documentación XML
En sucesivos artículos iremos describiendo mas en detalle esta herramienta de contratos de .NET. Para finalizar dejamos el código del ejemplo base de la librería, una clase que representa números racionales. Dicho ejemplo es fácil de leer y de comprender si se conoce el concepto de contratos, mas allá de los detalles de Microsoft Code Contracts.
  public class Rational {
    public int Numerator { get; protected set; }
    public int Denominator { get; protected set; }

    public Rational(int n, int d) {
      Contract.Requires(d != 0);

      this.Numerator = n;
      this.Denominator = d;
    }

    [ContractInvariantMethod]
    private void RationalInvariant() {
      Contract.Invariant(Denominator != 0);
    }

    public virtual void Add(Rational other) {
      Contract.Requires(other != null);
      int newN = this.Numerator * other.Denominator + other.Numerator * this.Denominator;
      int newD = this.Denominator * other.Denominator;

      this.Numerator = newN;
      this.Denominator = newD;
    }

    public static Rational operator +(Rational a, Rational b) {
      Contract.Requires(a != null);
      Contract.Requires(b != null);
      return new Rational(a.Numerator * b.Denominator + b.Numerator * a.Denominator, a.Denominator * b.Denominator);
    }
    public static Rational operator +(Rational a, int b) {
      Contract.Requires(a != null);
      return new Rational(a.Numerator + b * a.Denominator, a.Denominator);
    }

    public virtual void Divide(int divisor)
    {
      Contract.Requires(divisor != 0);

      this.Denominator = this.Denominator * divisor;
    }

    public int Truncate()
    {
      return this.Numerator / this.Denominator;
    }

    public virtual void Invert() {
      Contract.Ensures(Contract.OldValue(this.Numerator) == this.Denominator &&    Contract.OldValue(this.Denominator) == this.Numerator);

      int num = this.Numerator;
      int den = this.Denominator;
      this.Numerator = den;
      this.Denominator = num;
    }

  }

No hay comentarios:

Publicar un comentario