При работе с контрактами существует несколько неприятных вещей, которые приходится обходить. Например, не к ночи помянутый Liskov Substitution Principle, которого придерживаются разработчики Contracts.
Например, у нас есть некий класс, который наследует интерфейс из внешней библиотеки. И мы определяем в классе реализацию метода из этого интерфейса:
public class A : Interface1
{
public void MethodInterface1( object sender, Event e) {...}
}
Так вот, засада в том, что согласно описанных выше принципов — мы не должны напрямую проверять приходящие значения, т.к. это — ответственность постусловий библиотеки, поставщика интерфейса. Т.е. подобный код — считается некорректным:
public void MethodInterface1( object sender, Event e)
{
Contract.Requires(sender != null, "Sender is null");
Contract.Requires(event != null, "Event object is null");
...
}
Мало того, даже такая реализация будет выдавать предупреждение (warning CC1033):
public void MethodInterface1( object sender, Event e)
{
if (sender == null) throw new ArgumentNullException("sender", "Event sender is null.");
if (evt == null) throw new ArgumentNullException("evt", "Event object is null.");
Contract.EndContractBlock();
...
}
Видимо, разработчики надеются, что создатели интерфейсов соображают в правилах наследования и теории построеннии иерархий чуть больше, чем обычно…
Приходится в обработке подобных отнаследованных интерфейсов вместо контрактов использовать старый способ валидации, убрав контрактную спецификацию. Таким образом, итоговый вариант будет выглядеть так:
public void MethodInterface1( object sender, Event e)
{
if (sender == null) throw new ArgumentNullException("sender", "Event sender is null.");
if (evt == null) throw new ArgumentNullException("evt", "Event object is null.");
...
}