Разница между переменной-членом и свойством-членом? - PullRequest
16 голосов
/ 17 февраля 2010

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

public class Car
{

    int speed; //Is this sufficient enough if Car will only set and get it.

    public Car(int initialSpeed)
    {
        speed = initialSpeed;
    }

    //Is this actually necessary, is it only for setting and getting the member
        //variable or does it add some benefit to it, such as caching and if so,
        //how does caching work with properties.
    public int Speed 
    {
        get{return speed;}
        set{speed = value;}
    }

        //Which is better?
        public void MultiplySpeed(int multiply)
        {
            speed = speed * multiply; //Line 1
            this.Speed = this.Speed * multiply; //Line 2

            //Change speed value many times
            speed = speed + speed + speed;
            speed = speed * speed;
            speed = speed / 3;
            speed = speed - 4;

        }
}

В приведенном выше примере, если у меня нет свойства Speed ​​для установки и получения переменной скорости, и я решил изменить int speed на int spd, мне придется менять скорость на spd везде, где он используется, однако если я использую свойство, такое как Speed, для установки и получения скорости, мне просто нужно будет изменить скорость на spd в свойстве get и set свойства, поэтому в моем методе MutilplySpeed ​​такие вещи, как выше this.Speed ​​= this.Speed ​​+ this .Speed ​​+ this.Speed ​​не сломается.

Ответы [ 8 ]

23 голосов
/ 17 февраля 2010

Если переменная private, я часто не буду создавать для нее свойство. Если он каким-либо образом выставлен вне типа, я всегда выставляю его через свойство по разным причинам:

  • Это может быть не нужно сегодня, но если это станет необходимым позже, это серьезное изменение
  • Привязка данных работает только для свойств, а не для полей (я думаю, не большой пользователь привязки данных)
  • Позволяет вставлять проверки, ведение журнала, точки останова при доступе к значению

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

Обновление
В ответ на ваши обновленные примеры кода: здесь есть несколько вещей, которые следует учитывать при разработке кода.

  • Читаемость против скорости
  • "атомарность"
  • Другие побочные эффекты

Один типичный совет (который я считаю очень хорошим) - «пиши для ясности, проверяй на производительность». Это означает, что когда вы пишете свой код, вашей первой заботой должно быть, понятно ли, что делает код, глядя на него. Это часто (но не всегда) более важно, чем скорость кода. Напишите оптимизацию скорости, когда вы установили, где вы ее получаете. Доступ к свойству будет немного медленнее, чем непосредственное чтение поля, но в большинстве случаев разница будет незначительной (если вообще измеримой).

Атомность может быть проблемой. Учитывая ваш пример кода, у нас есть поле speed, которое открыто публикуется через свойство Speed. Если метод MultiplySpeed должен выполнить несколько обновлений значения, эти промежуточные значения будут доступны через свойство Speed в разное время, пока выполняется вычисление. Это верно независимо от того, обновляете ли вы поле напрямую или через свойство. В подобных случаях, возможно, лучше сначала поместить значение в локальную переменную, использовать его для вычислений и при необходимости присвоить значение этой переменной свойству.

Наконец, другие побочные эффекты. Возможно, что изменение значения Speed должно вызвать событие (например, SpeedChanged). В подобных случаях, вероятно, также не рекомендуется обновлять данные до тех пор, пока не будут выполнены расчеты.

Мне нравится думать о недвижимости как о контракте , а о поле - как реализация . Любой (за исключением ядра моего типа), которому нужно значение, должен использовать контракт. Опора на реализацию должна быть сделана, только если есть веские причины для обхода контракта.

И да, если вы инкапсулируете доступ к полю в свойстве, естественное изменение имени поля потребует меньше обновлений (и, возможно, имя поля станет менее важным).

Надеюсь, это имеет смысл, и это не так уж много не по теме;)

8 голосов
/ 17 февраля 2010

Я согласен с ответом Фредерика . Следовать его совету несколько сложнее - использовать автоматические свойства. Это просто свойства, которые автоматически генерируют стандартную логику получения / установки. Вы не получаете никакой проверки, но вы всегда можете заменить автоматическое свойство стандартным позже. Эта замена не является критическим изменением.

Здесь я заменил свойство Speed ​​в вашем примере на автоматическое свойство. Обратите внимание, что переменная-член исчезает, и ваш класс должен получить к ней доступ через свойство.

public class Car
{
    public Car(int initialSpeed)
    {
        Speed = initialSpeed;
    }

    public int Speed { get; set; }

    public void MultiplySpeed(int multiply)
    {
        Speed *= multiply;
    }
}

Вы также можете использовать другой вариант, называемый "получить с закрытым набором". Это означает, что получатель является общедоступным, но установщик является частным. Вы определяете это так:

    public int Speed { get; private set; }

Что касается вашего вопроса о префиксе this., он обычно не имеет значения. Это имеет значение только тогда, когда вы определили параметр метода или локальную переменную с тем же именем, что и переменная-член. Затем вы можете использовать this для доступа к переменной-члену.

1 голос
/ 17 февраля 2010

Дело в том, что нет большой разницы между публично объявленным полем и публичным свойством с частным резервным хранилищем, если нет дополнительной логики. При этом, все еще считается наилучшей практикой использования свойств.

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

1 голос
/ 17 февраля 2010

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

Не позволяйте сторонникам ОО сказать вам, что использовать открытые поля с философской точки зрения неправильно, хотя я могу согласиться с тем, что авто-свойства делают аргумент несколько спорным.

1 голос
/ 17 февраля 2010

это не добавляет кеширование, но оно обеспечивает согласованный интерфейс.

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

Также внутри класса вы должны снова получить доступ к свойству для согласованности (представьте вышеописанный сценарий, где у вас был класс, который напрямую обращался к переменной-члену).

1 голос
/ 17 февраля 2010

Такие вещи, как проверка могут быть покрыты в одном месте. Член инкапсулирован, и вам нужно беспокоиться о проверке и других вещах из вашего класса.

В вашем текущем сценарии это не имеет большого значения, но когда вам нужно изменить переменную или добавить поведение, проще использовать свойства, потому что у вас есть только одно место, где вам нужно его изменить.

0 голосов
/ 04 июля 2011

На мой взгляд дизайн языка нарушен. Не должно быть двух способов делать вещи, которые имеют столько семантического перекрытия. Свойства / Поля должны были обеспечивать преимущества любого подхода в зависимости от того, как они используются. Если программа минимально использует свойства Property, они должны действовать так же, как поля. Кроме того, не должно быть необходимости объявлять пустое значение get; и установить; методы в этом случае. Различия кажутся мне искусственными.

Это отличный язык; и довольно чистый по большей части. Это не значит, что это не должно быть улучшено в «следующий раз».

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

Одна вещь, которую вы забыли упомянуть, свойства помогут вам, когда вы продлите свой класс. Если ваш класс правильно спроектирован, ваши переменные внутри базового класса должны быть private. Без фактических свойств public свойства, которые есть У вас не будет доступа к этим закрытым переменным из вашего расширенного класса. Мы говорим публично против частного, и я не в том числе защищен по причине:).

Несколько замечаний, которые стоит упомянуть:

  • свойства помогают при расширении класса
  • свойств для меня делают код немного более читабельным (кроме this.privateVariable и PublicPropertyVariableName)
  • свойства могут обеспечить чтение, закрытые наборы, общедоступные получения и т. Д. (Гораздо более читабельные для других программистов). Рассмотрим случай, когда для IDentifier требуется публичное получение, но закрытый набор
  • Лично мне слишком много запросов / наборов, кажется, усложняет код, делает код менее читабельным, слишком много лишнего ненужного синтаксиса
  • наследование / расширение до расширенного класса не позволяет вам наследовать частные переменные, свойства - это ответ. (опять же, здесь нет упоминаний о защите, это другая история)
  • Мне, даже если у класса есть закрытая переменная, мои методы класса все еще используют свойство для доступа или использования этой закрытой переменной
  • Не забывайте о проверке, это значительно упрощает проверку, особенно с точки зрения читаемости.

Это просто некоторые общие вещи (хотя мои 2 цента, хотя на большинстве из них).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...