Using code contracts on abstract classes

If you use abstract classes in your code, you will know that being able to control how they are used with code contracts will result in more robust code. But how exactly can we use code contracts with abstract classes? Especially since abstract classes are supposed to contain no implementation? Well, it is definitely possible, and here is how we do it.

Getting ready

If you have not worked with abstract classes before, we advise you to first read Chapter 2, Classes and Generics, to familiarise yourself with how abstract classes are used and created.

How to do it…

  1. Before you go on, ensure that you have added the code contracts using statement to the top of your Recipes.cs class file:
    using System.Diagnostics.Contracts;
  2. Create an abstract class called Shape that defines two methods called Length() and Width() which each take an integer value as a parameter. Remember that abstract classes contain no implementation:
    public abstract class Shape
    {
        public abstract void Length(int value);
        public abstract void Width(int value);
    }
  3. Create another abstract class called ShapeContract that inherits the Shape abstract class. It is here that our code contracts will reside:
    public abstract class ShapeContract : Shape
    {
        
    }
  4. Override the Length() and Width() methods of the Shape abstract class and ensure that they require a non-zero parameter:
    public abstract class ShapeContract : Shape
    {
        public override void Length(int value)
        {
            Contract.Requires(value > 0, "Length must be greater than zero");
        }
    
        public override void Width(int value)
        {
            Contract.Requires(value > 0, "Width must be greater than zero");
        }
    }
  5. We now need to associate the ShapeContract contract class to the Shape abstract class. We will do this via the use of attributes. Add the following attribute to the top of your Shape abstract class:
    [ContractClass(typeof(ShapeContract))]
  6. After doing this, your Shape abstract class will look like this:
    [ContractClass(typeof(ShapeContract))]
    public abstract class Shape
    {
        public abstract void Length(int value);
        public abstract void Width(int value);
    }
  7. We also need to associate the Shape abstract class to the ShapeContract abstract class as a means of telling the compiler which class the contracts need to act upon. We will do this by adding the following attribute to the top of the ShapeContract class:
    [ContractClassFor(typeof(Shape))]
  8. When you have done this, your ShapeContract class will look like this:
    [ContractClassFor(typeof(Shape))]
    public abstract class ShapeContract : Shape
    {
        public override void Length(int value)
        {
            Contract.Requires(value > 0, "Length must be greater than zero");
        }
    
        public override void Width(int value)
        {
            Contract.Requires(value > 0, "Width must be greater than zero");
        }
    }
  9. We are now ready to implement the Shape abstract class. Create a new class called Rectangle and inherit the Shape abstract class:
    public class Rectangle : Shape
    {
            
    }
  10. You will notice that Visual Studio underlines the Rectangle class with a red squiggly line. This is because no implementation of the Shape class exists yet. Hover your mouse cursor over the red squiggly line and look at the lightbulb pop-up suggestion provided by Visual Studio:
    How to do it…
  11. By holding down Ctrl + . (period), you will see the suggested fixes that you can implement to correct the error that Visual Studio is warning you about. In this instance, there is only a single fix that Visual Studio suggests we implement, which is to implement the abstract class:
    How to do it…
  12. After you have clicked on the Implement Abstract Class suggestion in the lightbulb suggestion, Visual Studio will insert the implementation of the Shape abstract class. You will notice that the methods inserted for you still don't contain any implementation and will throw NotImplementedException if you don't add any implementation to the Length() and Width() methods:
    How to do it…
  13. To add implementation to our Rectangle class, create two properties for the Length() and Width() methods and set these properties equal to the value of the supplied parameter value:
    public class Rectangle : Shape
    {
        private int _length { get; set; }
        private int _width { get; set; }
        public override void Length(int value)
        {
            _length = value;
        }
    
        public override void Width(int value)
        {
            _width = value;
        }
    }
  14. In the console application, add the relevant using statement to the Program.cs class to bring the Chapter8 class into scope:
    using Chapter8;
  15. Create a new instance of the Rectangle class and pass some values to the Length() and Width() methods of the Rectangle class:
    try
    {
        Rectangle oRectangle = new Rectangle();
        oRectangle.Length(0);
        oRectangle.Width(1);
    }
    catch (Exception ex)
    {
        WriteLine(ex.Message);
    }
    ReadLine();
  16. Finally, run the console application and inspect the output window:
    How to do it…

How it works…

As we have added a zero value to the Length() method, the code contract on the abstract class has correctly thrown an exception. Being able to implement code contracts on abstract classes allows developers to create better code, especially when working in teams where you need to convey implementation limitations based on certain business rules.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.104.95