Вписываются ли инвариантные утверждения в программирование на C #? - PullRequest
7 голосов
/ 03 января 2011

В книге Кодеры за работой автор спрашивает: «Как вы используете инварианты в своем коде». Пожалуйста, объясните, что означает этот вопрос.

Я видел инварианты класса в вики , но пример приведен на Java, и я не достаточно опытен в Java, чтобы связать этот пример с C #. .NET 4.0 вводит инвариантность, ковариацию и контравариантность и хорошо объяснена здесь . Инвариантность настолько широка. Использование этого слова авторами, похоже, связано с модульным тестом. Что означает автор для тех, кто читает книгу? Мы говорим о том, чтобы сделать предположение и просто проверить достоверность после модульного теста?

Ответы [ 4 ]

10 голосов
/ 03 января 2011

Слово инвариант не означает, что что-то не меняется при определенных условиях.Есть много разных видов инвариантов.Например, в физике скорость света инвариантна при преобразовании Лоренца, т.е. она не меняется, если вы переходите в систему отсчета.В программировании тоже есть много видов инвариантов.Есть инварианты классов, которые не меняются в течение жизни объекта, инварианты методов, которые не меняются в течение жизни функции, ...

Инвариант класса - это то, что всегда (по крайней мере, вобщедоступные времена) верно для экземпляра этого класса.

Это никоим образом не связано с ко / противо-дисперсией.Co- / Contra-дисперсия описывает, какие типы могут быть заменены другими типами с другими (общими) параметрами или возвращаемыми типами.Хотя вы можете вызывать что-то инвариантное, потому что оно не поддерживает Co- / Contra-дисперсию, это совершенно другой вид инвариантности, чем инвариант класса или метода.

Например, некоторый набор может иметь следующие инварианты:

  • data! = Null
  • Размер> = 0
  • Емкость> = 0
  • Размер <= Емкость </li>

С этим классом:

class MyCollection<T>
{
  private T[] data;
  private int size;

  public MyCollection()
  {
    data=new T[4];
  }

  public int Size{get{return size;}}
  public int Capacity{get{return data.Length;}}

  [ContractInvariantMethod]
  protected void ClassInvariant()
  {
    Contract.Invariant(data != null);
    Contract.Invariant(Size >= 0);
    Contract.Invariant(Capacity >= 0);
    Contract.Invariant(Size < Capacity);
  }
}

Почти у каждого класса есть некоторые инварианты, но не каждый их применяет..net 4 добавляет хороший способ документировать и утверждать их, используя кодовые контракты.

2 голосов
/ 03 января 2011

Этот пример в Wiki - это реализация инвариантов с JML, который является очень специфической, экзотической и, возможно, хорошо продуманной исследовательской технологией, но вообще не является необходимым мейнстримом.Кроме того, речь идет не только об инвариантах, но и о том, что утверждение мутатора сделало то, что ожидалось, а это не то, о чем я думаю, когда думаю об инвариантах.Я не читал Coders at Work, но я сомневаюсь, что кто-нибудь в Coders at Work использовал JML.

В любом случае, я всегда думал, что инварианты - это отличный способ «рано рухнуть» и не дать вашему коду пытаться делать разумные вещикогда фактически состояние программы находится в необоснованном (незапланированном) состоянии.

Хороший пример инварианта в коде C # может состоять в том, чтобы никогда не отдавать объект в N-Hibernate для сохранения, если этот объект не был переданна его инварианты, которых должно быть много, чтобы не допустить попадания нечувственных данных в базу данных.Давайте посмотрим, смогу ли я вспомнить другие примеры ...

  • Предположим, у вас есть класс User, который всегда должен иметь свойство основного адреса электронной почты, а затем инвариант, который нужно проверить перед сохранением.может быть, чтобы убедиться, что поле адреса электронной почты не пустое.В противном случае другая логика приложения, предполагающая, что адреса электронной почты существуют для всех пользователей, может испортиться при попытке отправить пользователю электронное письмо позже.

  • Предположим, что у объекта пользователя "много«Объекты электронной почты, и предположим, что для электронной почты не имеет смысла существовать без принадлежащего ей пользователя, тогда инвариант класса электронной почты может быть для того, чтобы ссылка электронной почты на его пользователя всегда была не нулевой, иначе выпотерянный объект электронной почты, который может привести к исключениям нулевого указателя при попытке обратиться к владельцу электронной почты.

  • Предположим, вы пишете графический интерфейс, который должен отображать статус AmazonS3 объект в обычной форме WPF.Инвариант в форме может заключаться в том, чтобы убедиться, что форма правильно связана с ее объектом, прежде чем выполнять какие-либо обработчики событий в этой форме.

  • Предположим, вы пишете StackOverflow.Инвариант здесь может заключаться в том, чтобы убедиться, что уровень репутации пользователя никогда не бывает отрицательным, даже если пользователь применяет штрафы за репутацию.Отрицательная репутация может сломать те симпатичные графики, которые отображают опыт как функцию времени (если только эти графики не подготовлены для построения линий ниже оси 0, что вполне может быть ...).

Что касается того, когда проверять инварианты, вы можете сделать это в конце любого метода, который изменяет состояние данных.На самом агрессивном и параноидальном уровне защитного программирования вы можете проверить инвариант до и после всех методов.

2 голосов
/ 03 января 2011

В этом случае инварианты означают условия, которые применяются к параметрам и которые остаются верными в течение всего срока службы функции / метода.

С wikipedia :

В информатике предикат называется инвариантом последовательности операций при условии, что: если предикат имеет значение true до начала последовательности, то он равен true в конце последовательности.

В .NET инварианты могут быть проверены / применены с помощью Code Contracts .

1 голос
/ 03 января 2011

Значение в этом контексте не связано с дисперсией co и contra для генериков, представленных в C # 4, а скорее в том же смысле, что и статья в Википедии, на которую вы ссылаетесь. В C # это могут быть отладочные утверждения (т.е. Debug.Assert(condition)), а также библиотека контрактов кода. Например, есть ContractInvariantMethodAttribute, который можно применить к методу в классе, который утверждает инварианты класса:

[ContractInvariantMethod]
protected void ClassInvariant()
{
    Contract.Invariant(someCondition);
}
...