2010-05-04 5 views
10

Я использую свой собственный ArrayList для школьных целей, но для того, чтобы немного подправить вещи, я пытаюсь использовать контракты на код C# 4.0. Все было в порядке, пока мне не пришлось добавлять Контракты к конструкторам. Должен ли я добавлять Contract.Ensures() в пустой конструктор параметров?Дизайн по контрактам и конструкторам

public ArrayList(int capacity) { 
     Contract.Requires(capacity > 0); 
     Contract.Ensures(Size == capacity); 

     _array = new T[capacity]; 
    } 

    public ArrayList() : this(32) { 
     Contract.Ensures(Size == 32); 
    } 

Я бы сказал, что да, каждый метод должен иметь четко определенный договор. С другой стороны, зачем говорить, если он просто делегирует работу «главному» конструктору? По логике, мне было бы не нужно.

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

Кроме того, есть ли какие-нибудь книги вокруг, которые идут немного глубже в отношении принципов и использования Проекта по контрактам? Одна вещь - знание синтаксиса использования Контрактов на языке (C# в данном случае), другое - знание того, как и когда его использовать. Я прочитал несколько уроков и статью о нем в статье «С # в глубине» Джона Скита, но я хотел бы пойти немного глубже, если это возможно.

Благодаря

+0

связаны: http://stackoverflow.com/questions/2539497/code-contracts-do-we-have-to-specify-contract-requires-statements-redundant/2626997 – porges

+0

Вы могли бы избавиться от «Контракта. Требуется (емкость> 0); если вы сделаете c'tor, возьмите uint, противоположный int. Я пытаюсь использовать Контракты в качестве последнего средства, где язык ограничивает вашу способность позволить следующему разработчику знать, о чем вы думали, когда вы создали код в первую очередь. Если вы решите сохранить контракт, я бы написал «Contract.Requires (capacity> = 0)»; поскольку всегда нужно иметь возможность создавать пустую структуру данных, а затем иметь возможность добавлять объекты позже. –

+0

«... в будущем у нас есть поддержка Intelisense для контрактов». Будущее - сегодня! http://visualstudiogallery.msdn.microsoft.com/1ec7db13-3363-46c9-851f-1ce455f66970 –

ответ

5

Я полностью не согласен с ответом Томаса. Пока вы делаете выбор в реализации ArrayList(), у вас должен быть контракт на него, который документирует эти варианты.

Здесь вы делаете выбор вызова главного конструктора с аргументом 32. Есть много других вещей, которые вы могли бы решить (не только в отношении выбора размера по умолчанию). Предоставление контракта ArrayList(), который почти идентичен документам ArrayList(int), которые вы решили не выполнять большинство глупых вещей, которые вы могли бы сделать, вместо того, чтобы называть их напрямую.

Ответ: «Он называет главный конструктор, поэтому пусть контракт основного конструктора выполняет эту работу» полностью игнорирует тот факт, что контракт заключается в том, чтобы спасти вас от необходимости взглянуть на реализацию. Для стратегии проверки, основанной на проверке проверки выполнения во время выполнения, недостатком написания контрактов даже для таких коротких конструкторов/методов, которые почти непосредственно называют другой конструктор/метод, является то, что вы в конечном итоге проверяете вещи дважды. Да, это кажется излишним, но проверка утверждения во время выполнения является только одной стратегией проверки, а принципы DbC независимы от нее. Принцип: если его можно назвать, ему нужен контракт, чтобы документировать, что он делает.

+1

Да; и если вы используете статическую проверку, то это скажет вам это :) – porges

0

UMH, я не совсем понимаю, почему вы положили «Гарантирует» также в c'tor по умолчанию. Поскольку он вызывает основной c'tor, который уже выполняет полный контракт, по умолчанию c'tor делает это также - по определению. Так что это логическая избыточность и, следовательно, большой «Do not». Может быть, это может иметь прагматические последствия, как вы говорите, - не знаете коду контрактов, что хорошие ...

Что касается литературы - лучшие источники:

НТН! Thomas

+0

Предполагая, что в один прекрасный день Intelisense полностью поддерживает кодовые контракты (или полагая, что на сегодняшний день мы рассмотрим документацию по контрактам XML), явно заявив, что контракт конструктора no-args будет иметь выгоду, позволяющую клиенту ознакомиться с контрактом. Если вы оставите его пустым, вы не сможете. И именно поэтому я создал этот пост. –

+1

Я понимаю логическое обоснование, и, возможно, это станет правдой в один прекрасный день ... Но делаю. потому что, возможно, в будущем выгоды могут оказаться одной из худших (и самых дорогих) вещей в разработке программного обеспечения. Всегда делайте простейшую вещь, которая выполняет эту работу! –

+0

Да, у вас есть точка. Что, если Intelisense поддерживает эту функцию на сегодняшний день? Тогда было бы целесообразно поставить этот Контракт в конструктор no args? –

1

код клиента (используя контракты кода), который использует ArrayList не будет знать, что пустой конструктор Ensure s, что Size == 32, если явно не оговорено так, используя Ensure.

Так (например):

var x = new ArrayList(); 
Contract.Assert(x.Size == 32) 

даст вам предупреждение "как утверждают не доказано".

Вам необходимо явно указать все контракты; код контракты ReWriter/статические проверки не будут «смотреть через» метод, чтобы увидеть какие-либо последствия — см my answer to the related question "Do we have to specify Contract.Requires(…) statements redundantly in delegating methods?"

0

дизайна по контракту происходит от математических корней функционального программирования: Preconditions и Postconditions.

Вам действительно не нужна книга по этому вопросу, это не более чем часть степени компьютерной науки (большинство из них научат концепции). Основная предпосылка заключается в том, что вы пишете предпосылки, которые ожидает функция, и вывод, который он будет производить с учетом правильных параметров. Функция не будет работать с неправильными начальными параметрами. То же самое можно сказать и о алгоритме: он непогрешимый, то есть гарантированно обеспечить ожидаемый результат.

Вот как меня научили этому в той степени, в которой я сейчас участвую, но могут быть более четкие определения. Статья Википедии о разработке по контракту написана с наклонением OO, но pre/postconditions не зависят от языка.

+0

Да, я хочу сказать, что на бумажном дизайне OO не так много, чтобы учиться. Вы узнаете о классах, наследовании и инкапсуляции, и кажется, что это не намного больше, чтобы учиться. Но на практике существует множество книг о том, как делать хорошие программы OO. Иногда зная синтаксис и «теорию», недостаточно. –

+0

Это, вероятно, книги Wrox и apress, которые касаются практичности :) Гораздо больше глубины преподаются в (приличной) степени –

+0

У меня нет степени, так что мне делать? –

1

Я рекомендую читать Object Oriented Software Construction, 2nd Edition, или, может быть, Touch of Class, как от Бертрана Майера. Кроме того, вы можете прочитать статью 1992 года Applying "Design by Contract" от того же автора.

Резюмируя:

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

Так что в вашем случае сосредоточьтесь на инварианте. Создайте правильный объект (тот, который удовлетворяет инварианту класса), независимо от того, какой вызов вызывается.

В этом related answer Обсуждались похожие темы, включая пример.