Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
DZone MVB

Links

Social

Code contracts and inheritance

In my last posting about code contracts I introduced you how to force code contracts to classes through interfaces. In this posting I will go step further and I will show you how code contracts work in the case of inherited classes.

As a first thing let’s take a look at my interface and code contracts.


[ContractClass(typeof(ProductContracts))]

public interface IProduct

{

    int Id { get; set; }

    string Name { get; set; }

    decimal Weight { get; set; }

    decimal Price { get; set; }

}

 

[ContractClassFor(typeof(IProduct))]

internal sealed class ProductContracts : IProduct

{

    private ProductContracts() { }

 

    int IProduct.Id

    {

        get

        {

            return default(int);

        }

        set

        {

            Contract.Requires(value > 0);

        }

    }

 

    string IProduct.Name

    {

        get

        {

            return default(string);

        }

        set

        {

            Contract.Requires(!string.IsNullOrWhiteSpace(value));

            Contract.Requires(value.Length <= 25);

        }

    }

 

    decimal IProduct.Weight

    {

        get

        {

            return default(decimal);

        }

        set

        {

            Contract.Requires(value > 3);

            Contract.Requires(value < 100);

        }

    }

 

    decimal IProduct.Price

    {

        get

        {

            return default(decimal);

        }

        set

        {

            Contract.Requires(value > 0);

            Contract.Requires(value < 100);

        }

    }

}


And here is the product class that inherits IProduct interface.


public class Product : IProduct

{

    public int Id { get; set; }

    public string Name { get; set; }

    public virtual decimal Weight { get; set; }

    public decimal Price { get; set; }

}


if we run this code and violate the code contract set to Id we will get ContractException.


public class Program

{

    static void Main(string[] args)

    {

        var product = new Product();

        product.Id = -100;

    }

}


 

Now let’s make Product to be abstract class and let’s define new class called Food that adds one more contract to Weight property.


public class Food : Product

{

    public override decimal Weight

    {

        get

        {

            return base.Weight;

        }

        set

        {

            Contract.Requires(value > 1);

            Contract.Requires(value < 10);

 

            base.Weight = value;

        }

    }

}


Now we should have the following rules at place for Food:

  1. weight must be greater than 1,
  2. weight must be greater than 3,
  3. weight must be less than 100,
  4. weight must be less than 10.

Interesting part is what happens when we try to violate the lower and upper limits of Food weight. To see what happens let’s try to violate rules #2 and #4. Just comment one of the last lines out in the following method to test another assignment.


public class Program

{

    static void Main(string[] args)

    {

        var food = new Food();

        food.Weight = 12;
        food.Weight = 2;

    }

}


And here are the results as pictures to see where exceptions are thrown. Click on images to see them at original size.

Code contracts inheritance: violation of lower limit Code contracts inheritance: violation of upper limit
Violation of lower limit. Violation of upper limit.

As you can see for both violations we get ContractException like expected.

Code contracts inheritance is powerful and at same time dangerous feature. Although you can always narrow down the conditions that come from more general classes it is possible to define impossible or conflicting contracts at different points in inheritance hierarchy.

Comments

James Michael Har said:

Very nice!  I'm curious, what's the performance cost of a contract vs non-contract?  I know you don't get something for nothing, but I was curious just how "heavy" it is.

# May 12, 2010 12:27 PM

DigiMortal said:

Thanks for question James!

I plan to make some performance measuring during next couple of days. So, stay tuned :)

# May 12, 2010 1:54 PM

curlyfro said:

why would we use class code contracts vs data annotation attributes?

# May 12, 2010 3:46 PM

Agge Kempff-Andersen said:

Isn´t it a violation of the Liskov substitution principle, when you are tightening the preconditions from w < 100 to w < 10?

It seems to me like something the code contract framework should catch and disallow.

I heard from Mike Barnett, that Code Contracts does not support the loosening of preconditions in derived classes, which seem even more weird if they allow them to be tightened.

# May 31, 2010 9:13 AM