Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как лучше всего использовать свойства .NET?

Автор вопроса: PICyourBrainОтветов: 7

Я немного смущен тем, сколько я ДОЛЖЕН делать со свойствами. Я слышал, что свойства всегда должны представлять логическое свойство класса. Get и Set почти никогда не должны генерировать исключения, за исключением ArgumentOutOfRange. Это правда? Является ли следующий пример совершенно неправильным?

public bool DeviceRegistered
{
    get{ return _Registered;}
    set
    {
        if(value)
        {
            RegisterDevice();
            _Registered = true;
        }
        else
        {
            UnRegisterDevice();
            _Registered = false;
        }
    }
}

Кроме того, если метод в том же классе хочет изменить значение свойства, должен ли он пройти через средство доступа set свойства или просто изменить частную переменную _Registered напрямую?

Если у вас есть какие-либо дополнительные советы по использованию свойств, пожалуйста, укажите! Спасибо

exceptionproperties

Ответы

Ответ 1 · рейтинг 6 · Richard Nienaber

Вот ссылка на Руководство по разработке свойств из MSDN. Обратите особое внимание на свойство и метод раздел.

Исходя из моего личного опыта, вы не должны использовать свойства для выполнения большого объема работы. Они должны возвращать информацию, которая уже была получена. В настоящее время я работаю над базой кода, которая имеет множество лениво загруженных свойств, которые извлекают информацию из веб-службы. Просмотр свойств класса во время отладки приводит к оценке всех свойств, что приводит к истечению времени функциональной оценки и сбою процесса ASP.NET.

Ответ 2 · рейтинг 4 · ChaosPandion

В этом случае я думаю, что более логично использовать методы, потому что вы выполняете действие.

private volatile bool _DeviceRegistered;
private readonly object _Lock = new object();

public bool DeviceRegistered
{
    get { return _DeviceRegistered; }
}

public void RegisterDevice()
{
    lock (_Lock) // A good idea to lock
    {
        // ........
        _DeviceRegistered = true;
    }
}

public void UnregisterDevice()
{
    lock (_Lock)
    {
        // ........
        _DeviceRegistered = false;
    }
}

Ответ 3 · рейтинг 1 · lance

Узкий ответ: мне нравится использовать свойства только для чтения, когда у меня есть значение, для получения которого требуется немного работы, но я хочу, чтобы "остальный мир" (даже вызывающие абоненты внутри тот же класс) рассматривать как переменную, значение которой всегда доступно. Свойство выполнит работу по получению значения, а затем просто вернет значение (возможно, с помощью таких оптимизаций, как кэширование и т. д.).

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

Ответ 4 · Shawn Steward

В этом случае, поскольку вы вызываете другой метод при изменении свойства, если вы хотите сохранить эту функциональность, установите ее с помощью Accessor. Если это просто сохранение значения, вам немного лучше использовать переменную _Registered напрямую.

Ответ 5 · tvanfosson

Я соглашусь с тем, что часто имеет смысл иметь свойство делать больше, чем просто хранить значение, но, на мой взгляд, ваш пример ужасен. У меня был бы метод, который регистрирует/отменяет регистрацию устройства, и простой геттер для текущего состояния. Мое общее правило заключается в том, что если я выполняю действие, я использую метод, но если я просто изменяю значение, то более подходящим является свойство. Теперь о том, как свойство обрабатывает это, может потребоваться выполнение некоторых вычислений или операций ввода-вывода, но важнее всего ожидания потребителя класса.

public void Register()
{
  ...do some stuff...
  this.Registered = true;
}

public void Unregister()
{
  ...do some stuff...
  this.Registered = false;
}

public bool Registered { get; private set; }

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

Ответ 6 · MaLio

Чтобы решить проблему использования поля напрямую или средства доступа/мутатора свойства, я поддерживаю свойство. Если вы должны иметь значение по умолчанию, возвращаемое в методе доступа, или вызывать события изменения свойства (или тому подобное) в мутаторе, вы обойдёте эту функцию, обратившись к полю напрямую. Если расширяющий класс переопределяет свойство, вы можете непреднамеренно обойти расширяющий класс при прямом доступе к полю.

Бывают случаи, когда доступ к полю (приватный) подходит, но я всегда отдаю предпочтение свойству, если только нет веских причин для доступа к полю.

Ответ 7 · Sam Harwell

Вот несколько правил, которые я понял со временем. Большинство из них являются моими мнениями, но мне нравится думать, что это хорошие идеи. :) Изменить: я только что понял, что большинство из них описаны в Использование ресурсов.

Добытчики

  • Вы должны предпочесть, чтобы геттеры не изменяли состояние. Если у вас есть геттер, который изменяет состояние программы, пометьте его [DebuggerBrowsable(DebuggerBrowsableState.Never)].
  • Предпочитайте, чтобы геттеры могли вызываться из любого потока.
  • Предпочитайте, чтобы геттеры вычислялись тривиально, так как они используются таким образом, что люди верят, что они не понесут потери производительности. Если их выполнение может занять некоторое время, пометьте их либо атрибутом DebuggerBrowsable, как указано выше, либо с помощью [DebuggerDisplay("Some display text")] (где текст тривиально вычисляется). Пренебрежение последним может отрицательно сказаться на производительности отладчика.
  • Getters can throw at least the following exceptions:
    • InvalidOperationException
    • ObjectDisposedException

Сеттеры

  • Предпочтите, чтобы всякий раз, когда вы устанавливаете два свойства подряд, не имело значения, какое из них будет первым.
  • Если у установщика есть предварительное условие, которое нельзя проверить с помощью общедоступных свойств, оно должно быть помечено как защищенное или закрытое.
  • Можно ограничить вызов сеттеров определенным потоком, но если вы это сделаете, это должно быть задокументировано, и ваш объект должен либо реализовывать ISynchronizeInvoke или предоставить объект Dispatcher.
  • Setters can throw at least the following exceptions:
    • An ArgumentException (ArgumentNullException, ArgumentOutOfRangeException, etc. as appropriate)
    • InvalidOperationException
    • ObjectDisposedException

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы