Когда использовать [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()может быть оформлен как чистый, и кодовые контракты не заметят ничего плохого.

    В настоящее время нет компонента Code Contracts, который проверяет, действительно ли методы, объявленные как pure, чисты. Таким образом, если программист украсил метод с помощью [Pure], он просто поверил.

    Из Кодекса № 5: Метод чистоты

  • .NET Framework содержит конструкторы, которые не являются чистыми. Например, List<T>(IEnumerable<T> collection)на самом деле нечисто, если цикл в коллекции имеет побочные эффекты.

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

    С другой стороны, если вам нужно 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.