Liskov Substitution Principle & Contracts

в 19:04, , рубрики: Песочница

При работе с контрактами существует несколько неприятных вещей, которые приходится обходить. Например, не к ночи помянутый 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.");
  ...
}

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js