Проектування за контрактом - ідея, запозичена з мови програмування Eiffel. В простір імен System.Diagnostics.Contracts версії .NET 4 включені класи для статичних перевірок коду і перевірок часу виконання, які можуть застосовуватися всіма мовами .NET.
За допомогою цієї функціональності можна визначати передумови, постумови і інваріанти всередині методу. Передумови перераховують вимоги, яким повинні задовольняти параметри, постумови визначають вимоги до повертається даними, а інваріанти - вимоги до змінних всередині самого методу.
Інформація про контракт може бути скомпільована в оцінний і робочий код. Можна також визначити окрему збірку контракту, і багато перевірки також можуть бути виконані статично, без запуску програми.
Контракти допускається визначати на інтерфейсах; це змусить реалізації інтерфейсів задовольняти вимоги цих контрактів. Інструменти для роботи з контрактами можуть переписати збірку, запровадивши перевірки контракту в код для їх виконання під час функціонування програми, перевіряти контракти під час компіляції і додавати інформацію про контракти в генерується документацію XML.
Контракти коду визначаються класом Contract. Всі вимоги контрактів, які задаються в методі, незалежно від того, є вони передумовою або постусловіем, повинні поміщатися в початок методу. Можна також призначити глобальний обробник події ContractFailed, який буде викликатися при кожному порушенні контракту під час виконання. Виклик SetHandled () з параметром е типу ContractFailedEventArgs припинить стандартну поведінку при збої з генерацією винятку.
Передумови (Requires)
Передумови перевіряють параметри, передані в метод Requires () і Requires
Показаний нижче контракт генерує виняток ArgumentNullException, якщо аргумент o дорівнює null. Виняток не генерується, якщо обробник події ContractFailed встановлює подія в handled (оброблено). Крім того, якщо у вікні властивостей проекту прапорець Assert on Contract Failure (Затвердження при порушенні контракту) відзначений, то замість генерації певного виключення викликається метод Trace.Assert () для припинення роботи програми:
виклик Requires
У величезній масі успадкованого коду аргументи часто перевіряються операторами if з генерацією винятку в разі порушення заданого умови. Завдяки контрактам коду, немає необхідності переписувати верифікацію. Досить лише додати один рядок коду:
EndContractBlock () визначає, що попередній код повинен бути оброблений як контракт. Якщо використовуються інші оператори контракту, то в EndContractBlock () немає необхідності.
Для перевірки колекцій, які використовуються в якості аргументів, в класі Contract передбачені методи Exists () і ForAll (). Метод ForAll () перевіряє кожен елемент в колекції на предмет відповідності умові. У наступному прикладі проводиться перевірка, що кожен елемент колекції має значення менше 12. За допомогою методу Exists () можна перевірити, чи відповідає умові хоча б один елемент колекції:
Обидва методи, Exists () і ForAll (), мають перевантаження, якій замість IEnumerable
Післяумови (Ensures)
Визначення постусловіем гарантує дотримання певних умов щодо поділюваних даних і значень. І хоча вони визначають деякі гарантії про що повертаються значеннях, проте, вони повинні записуватися на початку методу; всі вимоги контракту повинні визначатися на початку методу.
Ensures () і EnsuresOnThrow
За допомогою EnsuresOnThrow
Для гарантування повертається до контракту Ensures () може використовуватися спеціальне значення Result
Можна також порівнювати значення зі старим значенням. Це робиться за допомогою методу 01dValue
інваріанти
Інваріанти визначають контракти для змінних протягом часу життя методу. Contract.Requires () визначає вхідні вимоги, Contract.Ensures () - вимоги на кінець методу. Contract.Invariant () визначає умови, яких слід дотримуватися протягом часу життя методу: