Code Contracts in Interfaces are evaluated after Contracts in Class Implementations

I recently noticed an — at least for me — unexpected behaviour when working with Code Contracts in interfaces. When you define a contract for an interface (via ContractClassFor) and implement a class from that interface that contract is certainly enforced. However when you define additional requirements on that implementation class these contracts are evaluated BEFORE the interface contracts.

Here is a quick example to demonstrate the behaviour:

namespace biz.dfch.CS.Examples.CodeContracts
{
  [ContractClass(typeof(ContractClassForIInterfaceWithContract))]
  public interface IInterfaceWithContract
  {
    void Funcenstein(string parameter);
  }

  [ContractClassFor(typeof(IInterfaceWithContract))]
  abstract class ContractClassForIInterfaceWithContract : IInterfaceWithContract
  {
    public void Funcenstein(string parameter)
    {
      Contract.Requires(null != parameter);
    }
  }

  [TestClass]
  public class IInterfaceWithContractTest
  {
    class InterfaceWithContractImpl : IInterfaceWithContract
    {
      public void Funcenstein(string parameter)
      {
        // more restrictive requirement than on interface
        Contract.Requires(parameter.StartsWith("edgar"));

        return;
      }
    }

    [TestMethod]
    [ExpectContractFailure]
    public void CallingFuncensteinViolatesClassCodeContract()
    {
      // Arrange
      var parameter = "arbitrary-string-other-than-edgar";

      // Act
      var sut = new InterfaceWithContractImpl();
      sut.Funcenstein();
    }
  }
}

We define an interface IInterfaceWithContract that does not accept null strings on its Funcenstein method. The actual class implementation InterfaceWithContractImpl now requires a string that must StartWith edgar (which is more restrictive). Now we run into a problem, that the class implementation is evaluated first, which means we possibly de-reference a null pointer which would normally lead to getting the dreaded object reference not set to an instance of an object (but which is encapsulated by the __ContractsRuntime+ContractException exception.
If we had checked the contract from the interface first we would have gotten a more meaningful message (indicating that the whole string is actually null). Now we just get the message that the string does not start with edgar.

>> Test method biz.dfch.CS.Examples.CodeContracts.IInterfaceWithContractTest.
>> CallingFuncensteinViolatesClassCodeContract threw exception:
>> System.Diagnostics.Contracts.__ContractsRuntime+ContractException:
>> Precondition failed: parameter.StartsWith(“edgar”)

Just something to keep in mind when troubleshooting.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: