Как лучше всего использовать .NET Properties? - PullRequest
5 голосов
/ 25 февраля 2010

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

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

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

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

Ответы [ 7 ]

6 голосов
/ 25 февраля 2010

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

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

4 голосов
/ 25 февраля 2010

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

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;
    }
}
1 голос
/ 25 февраля 2010

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

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

0 голосов
/ 25 февраля 2010

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

Геттеры

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

Инкубационные

  • Предпочитают , что всякий раз, когда вы устанавливаете два свойства вплотную, не имеет значения, что будет первым.
  • Если сеттер имеет предварительное условие, которое не может быть проверено с помощью общедоступных свойств, его следует пометить как защищенное или личное.
  • Можно ограничить вызывающие сеттеры определенным потоком, но если вы это сделаете, это должно быть задокументировано, и ваш объект должен либо реализовать ISynchronizeInvoke, либо выставить Dispatcher собственность.
  • Сеттеры могут выдавать как минимум следующие исключения:
    • An ArgumentException (ArgumentNullException, ArgumentOutOfRangeException и т. Д. В зависимости от ситуации)
    • InvalidOperationException
    • ObjectDisposedException
0 голосов
/ 25 февраля 2010

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

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

0 голосов
/ 25 февраля 2010

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

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

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

public bool Registered { get; private set; }

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

0 голосов
/ 25 февраля 2010

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

...