Today I ran into a problem when all of a sudden my code contracts stopped working – as it seemed. In reality I was missing a simple override
in the implementation of a class that derived from a base class.
But now for a a concrete example. Suppose you have the following scenario:
- ContractClassForIArbitraryObject
this class holds the contract for the interfaceIArbitraryObject
- IArbitraryObject
this interface declares theInvoke
method - ArbitraryObjectBase
this abstract base class that might implement some default behaviour - ArbitraryObjectImpl
the actual implementation of the interface (via the base class)
Below you see an example implementation of the aforementioned classes:
[ContractClassFor(typeof(IArbitraryObject))] abstract class ContractClassForIArbitraryObject : IArbitraryObject { public bool IsActive { get; set; } public bool Invoke(object obj) { Contract.Requires(null != obj); return default(bool); } } [ContractClass(typeof(ContractClassForIArbitraryObject))] public interface IArbitraryObject { bool IsActive { get; set; } bool Invoke(object obj); } public abstract class ArbitraryObjectBase : IArbitraryObject { public virtual bool IsActive { get; set; } public virtual bool Invoke(object obj) { if(!IsActive) { return false; } // some magic code var result = 0 == (obj.GetType().ToString().Length % 2); return result; } } public class ArbitraryObjectImpl : ArbitraryObjectBase { public bool Invoke(object obj) { // some magic code ... return true; } }
When we now try to Invoke
a null
object from our instantiated ArbitraryObjectImpl
we should throw a Contract Exception
as the pre-condition null != obj
is not satisfied. However, the code will run just fine:
var arbitraryObjectImpl = new ArbitraryObjectImpl(); /// this will NOT throw a contract exception !!! arbitraryObjectImpl.Invoke(default(object));
The reason for this is, that we forgot to specify override
for the virtual
method in our base class. IF we define the ArbitraryObjectImpl
as shown in the example below (with the override
on the Invoke
method), CodeContracts will be checked and throw an exception (as expected):
public class ArbitraryObjectImpl : ArbitraryObjectBase { public override bool Invoke(object obj) { // some magic code ... return true; } }
The problem here really is not too hard to solve: just add the override
operator and we are done. But what is really annoying here is, that we do not get a compiler error in case we forgot the override
. And it becomes rather difficult to spot once we missed the operator. (We certainly can test it by writing unit tests …)