Contract interfaces & inheritance



    Let's talk about the dark side of power, namely, the problems in using contracts. About those cute little things that are carefully managed by the developers of the library and bring such a rather big fly in the ointment in a tiny pot of honey.


    Introduction.

    We assume that we read the classic document on MS Contracts, so we will immediately turn to such a convenient thing as the specification of interfaces for contract programming.

    http://research.microsoft.com/en-us/projects/contracts/
    http://download.microsoft.com/download/C/2/7/C2715F76-F56C-4D37-9231-EF8076B7EC13/userdoc.pdf

    If we have several public fields or methods, then once specifying the specification for these parameters within the interface, we can use a similar contract for real classes without additional scribbling. Having described the contract, you can then use it as a convenient magic wand.

    For example, we create a representative of the other side:

        public class TheDarkLord
        {
            public  string Name   { get; set; }
            private string SoName { get; set; }
            public TheDarkLord(string name, string soName)
            {
                this.Name   = name;
                this.SoName = soName;
            }
            public string ModifyBaseName(string updatedName)
            {
                this.Name = updatedName;
                return this.Name;
            }
        }
    


    It is possible that for the sake of future dark padovans, it will be necessary to use the described class as a base one. And, in order not to burden ourselves with unnecessary checks, we will set the specification for the public section, as well as complement the check and private at the same time.

    a) we will describe the interface
    b) we will not forget to create an abstract implementation on it that will incorporate the contract specification
    c) and extend the main class with support for checking the private section of the

    Implementation:

    a) interface and a link to the contract implementation

        [ContractClass(typeof(ITheDarkLordContract))]
        public interface ITheDarkLord
        {
            string Name { get; set; }
            string ModifyBaseName(string updatedName);
        }
    


    b) contract specification

        [ContractClassFor(typeof(ITheDarkLord))]
        public abstract class ITheDarkLordContract : ITheDarkLord
        {
            public string Name
            {
                get
                {
                    Contract.Ensures(!string.IsNullOrEmpty(Contract.Result()), 
                          "[ITheDarkLordContract] Name of Dark Lord is null or empty.");
                    return default(string);
                }
                set
                {
                    Contract.Requires(!string.IsNullOrEmpty(value), 
                          "[ITheDarkLordContract] Name of Dark Lord is null or empty.");
                }
            }
            public string ModifyBaseName(string updatedName)
            {
                Contract.Requires(!string.IsNullOrEmpty(updatedName), 
                        "[ITheDarkLordContract.ModifyBaseName] The new name of Dark Lord is null or empty.");
                Contract.Ensures(!string.IsNullOrEmpty(Contract.Result()), 
                        "[ITheDarkLordContract.ModifyBaseName] The updated name of Dark Lord is null or empty.");
                return default(string);
            }
        }
    


    c) the modified key class, to which we have attached the interface and private check

        public class TheDarkLord : ITheDarkLord
        {
            public  string Name   { get; set; }
            private string SoName { get; set; }
            [ContractInvariantMethod]
            private void DarkLordVerification()
            {
                Contract.Invariant(!string.IsNullOrEmpty(SoName));
            }
            public TheDarkLord(string name, string soName)
            {
                Contract.Requires(!string.IsNullOrEmpty(name));
                Contract.Requires(!string.IsNullOrEmpty(soName));
                this.Name   = name;
                this.SoName = soName;
            }
            public string ModifyBaseName(string updatedName)
            {
                this.Name = updatedName;
                return this.Name;
            }
        }
    


    The plot intrigue , which is the most unexpected ...

    Everything was fine with us until this moment. And then we took step number two - we used the described class as a derivative for:

        [ContractClass(typeof(ITheWhiteLordContract))]
        public interface ITheWhiteLord : ITheDarkLord
        {
            string UpdateAllNames(string name, string soName);
        }
        [ContractClassFor(typeof(ITheWhiteLord))]
        public abstract class ITheWhiteLordContract : ITheDarkLordContract, ITheWhiteLord
        {
            public string UpdateAllNames(string name, string soName)
            {
                return default(string);
            }
        }
    


    Everything seems to be beautiful - they created an heir for the interface, finalized a new abstract class and tried to compile. After that, they unexpectedly came up with a restriction on the number of times for the contract library: we cannot inherit contract classes from anyone except Object ... Clap - and the concept of inheritance for contract interfaces has collapsed ...

    Well, what do the developers recommend to us? And they act in a fantastic way: “take an abstract class, write in it the specification of the methods of the ancestor” ...

        [ContractClass(typeof(ITheWhiteLordContract))]
        public interface ITheWhiteLord : ITheDarkLord
        {
            string UpdateAllNames(string name, string soName);
        }
        [ContractClassFor(typeof(ITheWhiteLord))]
        public abstract class ITheWhiteLordContract : ITheWhiteLord
        {
            public string Name { get; set; }
            public string ModifyBaseName(string updatedName) 
            {
                return default(string);
            }
            public string UpdateAllNames(string name, string soName)
            {
                Contract.Requires(!string.IsNullOrEmpty(name), 
                      "[ITheWhiteLordContract.UpdateAllNames] The new name of White Lord is null or empty.");
                Contract.Requires(!string.IsNullOrEmpty(name), 
                      "[ITheWhiteLordContract.UpdateAllNames] The new soname of White Lord is null or empty.");
                Contract.Ensures(!string.IsNullOrEmpty(Contract.Result()),
                       "[ITheWhiteLordContract.UpdateAllNames] The updated name of White Lord is null or empty.");
                return default(string);
            }
        }
    


    Now imagine that in the base class we have about 10-20 fields that will have to be "pulled" up. A hierarchy may not be from one layer, but inherited through a group of classes. And after that, the proposed recommendation is akin to bullying.

    What did you get?

    Variants using interfaces as points for future Injections already fail. We'll have to remove inheritance in the contract interfaces and describe the calls to the objects we need as real classes.

    a) We specify the contract for the descendant

        [ContractClass(typeof(ITheWhiteLordContract))]
        public interface ITheWhiteLord
        {
            string UpdateAllNames(string name, string soName);
        }
        [ContractClassFor(typeof(ITheWhiteLord))]
        public abstract class ITheWhiteLordContract : ITheWhiteLord
        {
            public string UpdateAllNames(string name, string soName)
            {
                Contract.Requires(!string.IsNullOrEmpty(name), 
                         "[ITheWhiteLordContract.UpdateAllNames] The new name of White Lord is null or empty.");
                Contract.Requires(!string.IsNullOrEmpty(name), 
                         "[ITheWhiteLordContract.UpdateAllNames] The new soname of White Lord is null or empty.");
                Contract.Ensures(!string.IsNullOrEmpty(Contract.Result()), 
                         "[ITheWhiteLordContract.UpdateAllNames] The updated name of White Lord is null or empty.");
                return default(string);
            }
        }
    


    b) change the inheritance for the real class

        public class TheWhiteLord : TheDarkLord, ITheWhiteLord
        {
            public string UpdateAllNames(string name, string soName)
            {
                return this.Name;
            }
        }
    


    And now, instead of using interfaces, we will use access to the class specification:

    it was

        public class SpaceSheep
        {
            public ITheDarkLord AbstractLord { get; set; }
        }
    


    class implementation

        public class SpaceSheep
        {
            public TheDarkLord AbstractLord { get; set; }
        }
    


    From the point of view of system operability, we have not lost anything. If we have the TheWhiteLord class, then it is easy to inherit it from the dark side, gaining access to the necessary properties. At the same time, the operability of the used frameworks operating with IOC will not change. In fact, we can operate on any implementation for the specification of dependencies - interfaces, abstract classes or real ones.

    But the sediment remained. Who interfered with the creators of Contracts.Library to give us the opportunity to operate with interfaces not only to check valid public properties, but also to build a coherent inheritance architecture. Alas ...

    For a snack.

    Another minor inconvenience, which is desirable to remember. The specialization of private properties through ContractInvariantMethod imposes a slight limitation. Fields that are parsed in invariant methods must be specified in the constructor. Here is our class:

        public class TheDarkLord : ITheDarkLord
        {
            public  string Name   { get; set; }
            private string SoName { get; set; }
            [ContractInvariantMethod]
            private void DarkLordVerification()
            {
                Contract.Invariant(!string.IsNullOrEmpty(SoName));
            }
            ...
        }
    


    Here is an example of its creation:

       TheDarkLord lord = new TheDarkLord("James", "Bond");
    


    If we add an empty default constructor, we get a warning. Because the invariant method after exiting the constructor will check the conditions and return an Exception:

       CodeContracts: invariant is false: !string.IsNullOrEmpty(SoName)
    


    And a fairly convenient way to initialize class properties through a “deferred” assignment will not work:

       TheDarkLord secondLord = new TheDarkLord() { Name = "James" };
    


    You can rewrite the private property through an additional variable and check with the help of contracts, abandoning the invariants, but this will increase the amount of code and make it impossible to use the rather powerful and convenient tool post-condition verification ...

    PS . I don’t even stutter about messages displayed by contracts. It would seem - who's stopping to add a call stack disassembly handler and name generation automatically. But - the creators allow us to use only static lines, depriving us of the opportunity to replace this kind of code

       Contract.Requires(!string.IsNullOrEmpty(name), 
                 "[ITheWhiteLordContract.UpdateAllNames] The new name of White Lord is null or empty.");
    


    for something similar to

       Contract.Requires(!string.IsNullOrEmpty(name), 
                string.Format("{0} The new name of White Lord is null or empty.",GetCurrentMethod()));
    

    Also popular now: