Search code examples
c#-4.0code-contracts

Why can't I add Contract.Requires in an overridden method?


I'm using code contract (actually, learning using this).

I'm facing something weird to me... I override a method, defined in a 3rd party assembly. I want to add a Contract.Require statement like this:

public class MyClass: MyParentClass
{
    protected override void DoIt(MyParameter param)
    {
        Contract.Requires<ArgumentNullException>(param != null);

        this.ExecuteMyTask(param.Something);
    }

    protected void ExecuteMyTask(MyParameter param)
    {
        Contract.Requires<ArgumentNullException>(param != null);
        /* body of the method */
    }
}

However, I'm getting warnings like this:

Warning 1 CodeContracts: Method 'MyClass.DoIt(MyParameter)' overrides 'MyParentClass.DoIt(MyParameter))', thus cannot add Requires.

[edit] changed the code a bit to show alternatives issues [/edit]

If I remove the Contract.Requires in the DoIt method, I get another warning, telling me I have to provide unproven param != null I don't understand this warning. What is the cause, and can I solve it?


Solution

  • You can't add extra requirements which your callers may not know about. It violates Liskov's Subtitution Principle. The point of polymorphism is that a caller should be able to treat a reference which actually refers to an instance of your derived class as if it refers to an instance of the base class.

    Consider:

    MyParentClass foo = GetParentClassFromSomewhere();
    DoIt(null);
    

    If that's statically determined to be valid, it's wrong for your derived class to hold up its hands and say "No! You're not meant to call DoIt with a null argument!" The aim of static analysis of contracts is that you can determine validity of calls, logic etc at compile-time... so no extra restrictions can be added at execution time, which is what happens here due to polymorphism.

    A derived class can add guarantees about what it will do - what it will ensure - but it can't make any more demands from its callers for overridden methods.