Коли використовувати [Pure] на конструкторі?


19

Я дізнаюся про кодові контракти в .NET, і я намагаюся зрозуміти ідею чистих конструкторів. Документація кодових контрактів зазначає:

Усі способи, які викликаються в рамках договору, повинні бути чистими; тобто вони не повинні оновлювати будь-який попередній стан. Чистим методом дозволяється змінювати об'єкти, створені після вступу в чистий метод.

А в PureAttributeдокументації зазначено:

Вказує на те, що тип чи метод чистий, тобто він не вносить видимих ​​змін у стан.

Я розумію ці твердження, коли мова йде про методи, а як щодо конструкторів? Припустимо, у вас був такий клас:

public class Foo
{
    public int Value { get; set; }

    public Foo(int value) {
        this.Value = value;
    }
}

Цей конструктор, очевидно, впливає на стан нового Fooоб'єкта, але він не має інших побічних ефектів (наприклад, він не маніпулює жодними параметрами та не викликає будь-які нечисті методи). Це кандидат [Pure]чи ні? Яке значення розміщення [Pure]атрибута на конструкторі, і коли я повинен це зробити у власному коді?

Відповіді:


14

Ви прикрашаєте метод за допомогою [Pure]:

  • Якщо метод не має побічних ефектів. Наприклад, якщо метод отримує доступ до бази даних та модифікує її або її результат залежить від бази даних, це не є чисто.

  • І якщо ви розраховуєте використовувати його в кодових контрактах. Наприклад, якщо метод чистий , але ви не маєте наміру використовувати його в кодових контрактах, додавання [Pure]не матиме користі і не зробить ваш код швидшим.

Що стосується конструкторів, то, схоже, вони вважаються чистими в .NET і не потребують явного атрибуту. Я переглянув декілька конструкторів у джерелі .NET Framework, таких як атрибут у DateTimeних немає [Pure].

Я припускаю, що це робиться з кількох причин:

  • Це може бути занадто недоцільним, щоб писати конструктор без параметрів з [Pure]атрибутом просто, щоб мати можливість використовувати клас / структуру в контракті.

  • Деякі, наприклад String, не мають явних конструкторів.

  • Конструктори отримують спеціальну обробку навіть поза кодовими контрактами; наприклад, не передбачається, що викидатимете винятки всередині них .

  • [Pure]це лише умова, яка спрощує ваше життя, але немає фактичної статичної перевірки, щоб забезпечити чистоту методу, прикрашеного цим атрибутом. void DestroyDatabase()може вважатися чистою, а кодові договори не помітять нічого поганого.

    Наразі не існує жодного компонента кодових контрактів, який би перевіряв, чи методи, оголошені чистими, чисті. Таким чином, якщо програміст прикрасив метод методом [Pure], це просто віриться.

    З кодових контрактів №5: чистота методу

  • Сама .NET Framework містить конструктори, які не є чистими. Наприклад, List<T>(IEnumerable<T> collection)насправді нечисто, якщо прокручування колекції має побічні ефекти.

  • Контракти кричатимуться просто. Я легко можу уявити собі такий контракт Contract.Requires(!string.IsNullOrEmpty(name)), тому є вагомі підстави оголосити статику string.IsNullOrEmptyчистою.

    З іншого боку, якщо вам потрібен a StringBuilderдля того, щоб побудувати рядок, який ви будете перевіряти, то на предмет чогось, зателефонувавши до примірника методу вашого бізнес-класу, ви, мабуть, зловживаєте контрактами. Ось чому також StringBuilder.ToStringне позначається як чистий, навіть якщо це може бути (чи не так?)


Багато кодових контрактів щодо системних типів приймаються за перевірку контрактів, включаючи " будь-який метод, повноцінне ім'я якого починається з" System.Diagnostics.Contracts.Contract "," System.String "," System.IO.Path "або" System .Введіть " ". На жаль, я не впевнений, чи дивитися на типи .NET занадто корисно, якщо мова йде про кодові контракти.
pswg

3
Чистота - одна з тих речей, де весь названий код також повинен бути чистим або абонент не "чистий". Мені важко повірити, що всі конструктори за замовчуванням вважаються чистими.
Френк Хілеман

@FrankHileman: Я теж. Зараз у мене немає компілятора C #, але досить було б написати клас з конструктором і без [Pure]атрибуту, і використовувати його десь в договорі, щоб отримати остаточну відповідь.
Арсеній Мурценко

1

Об'єкт не можна використовувати, поки він не буде побудований у цьому випадку. Тому конструктор чистий. Якщо конструктор викликав інший код або викликав делегата, а інший код змінив властивість, що змінюється, це було б не чисто. Щоб бути безпечнішим, краще зробити властивість непорушною.


Отже, чистий конструктор - це чистий метод, якому дозволено змінювати стан поточного класу, доки він задовольняє інші умови чистоти? До речі, властивість є змінною, тому що я хотів підкреслити, що цей клас сам по собі не є чистим.
pswg

@pswg: Ви створили цікаве запитання, на яке, мабуть, повинен відповісти Microsoft. Припустимо, конструктор посилався на метод, що модифікував властивість, що змінюється; чи буде конструктор все-таки чистим? Я думаю, що технічно цього не було б, хоча модифікація "невидима" для зовнішніх глядачів. Оскільки в вашому оригінальному прикладі не існує іншого коду, він повинен бути чистим за будь-яким визначенням, про яке я думаю.
Френк Хілеман

@pswg: За винятком того, що набір властивостей є також методом виклику .. Я думаю, вам слід запитати на форумах MSDN.
Френк Хілеман

Я думаю, що якщо основна ідея чистоти полягає в тому, чи метод вносить якісь помітні зміни, то в цьому сенсі, незалежно від того, називає він чи не методи, до тих пір, поки зміни не може спостерігати жоден абонент, це все одно був би чистим методом.
pswg

@pswg: Це абстрактне визначення. Але якби я писав аналізатор для цих речей, ймовірно, дзвінок нечистого методу також вважався б таким, що робить абонент нечистим. Просто для простоти реалізації. Тоді питання полягає в тому, чи є конструктор звичайним методом виклику, або наскільки глибоко йде аналіз.
Френк Хілеман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.