Чи слід віддати перевагу властивостям із приватними полями чи без них?


16

У кодовій базі, в якій я зараз працюю, передбачено використання приватних полів та загальнодоступних властивостей. Наприклад, більшість класів мають таких членів:

// Fields
private double _foo;
private double _bar;
private double _baz;

// Properties
public double Foo
{
    get{ return _foo; }
    set{ _foo = value; }
}

public double Bar
{
    get{ return _bar; }
    set{ _bar = value; }
}

public double Baz
{
    get{ return _baz; }
}

Я знаю, що їх можна переписати без їх внутрішніх приватних властивостей:

public double Foo{ get; set; }
public double Bar{ get; set; }
public double Baz{ get; private set; }

Мені хотілося б дещо з цього приводу:

  • Чи є вагомі причини віддати перевагу старішому, більш чіткому стилю перед новим, більш стислим?
  • Чи слід писати якісь нові класи, використовуючи стислий стиль, чи намагатись відповідати старішому коду за послідовністю? Чи достатньо в цьому випадку послідовності, щоб виправдати старіший формат?


@PeterK. Інформативний. Не відповідає, чи варто мені турбуватися про дотримання стилю решти програми, чи це досить мала деталь, щоб не мати значення.
KChaloux

@KChaloux: Зрозумів! Ось чому це коментар, а не відповідь. :-)
Пітер К.

@PeterK. Ярмарок 'nuff = p
KChaloux

1
Ще одна причина не змінюватись, якщо щось передається через провід із WCF - автоматичні властивості мають проблеми з контрактом (через недійсні символи в іменах резервних полів, створених .NET)
Леон

Відповіді:


16

Є кілька випадків, коли так званий «старший» стиль все ж потрібен:

A: Незмінні типи, що використовують незмінність, надану мовою. readonlyМодифікатор в C # замерзає , що значення після будівництва. Неможливо імітувати це за допомогою автоматично реалізованих властивостей (поки).

public sealed class FooBarBazInator
{
    private readonly double foo;

    public FooBarBazInator(double foo)
    {
        this.foo = foo;
    }

    public double Foo
    {
        get
        {
            return this.foo;
        }
    }
}

В: Ваші геттери / сетери мають будь-яку логіку. Код WPF та Silverlight (і подібний), які пов'язані з вашими класами, будуть реалізовані INotifyPropertyChangedтак:

public class FooBarBazInator : INotifyPropertyChanged
{
    private double foo;

    public event PropertyChangedEventHandler PropertyChanged;

    public double Foo
    {
        get
        {
            return this.foo;
        }

        set
        {
            this.foo = value;
            this.RaisePropertyChanged("Foo");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        var propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Крім тих, я б сказав, використовуйте новий стиль. Зберігає ваш код стислим і пропонує меншу площу поверхні для помилок, щоб повзати. Плюс, якщо його колись потрібно змінити, щоб включити логіку, він не буде сумісний з підписами.


2
Здається, всі згодні з тим, щоб піти з новим стилем. Ви отримуєте +1 та кредит відповіді, коли ви розповіли мені про необхідність поля з readonlyмодифікатором, про який я не знав. = D
KChaloux

3
Деякі (включаючи мене) вважають автоматичні властивості приватного аксесуара "досить хорошими" для незмінних властивостей. Щоправда, вони можуть бути не по-справжньому непорушними, але ви просто повинні бути обережними, щоб не використовувати сеттер поза конструктором.
svick

2
Інший reaon - якщо ви хочете передати значення, refяке не працює з властивостями, тому вам потрібно поле
stijn

1
Такий інструмент, як Fody, може реалізовуватися INotifyPropertyChangedбез необхідності явних полів резервного копіювання . github.com/Fody/PropertyChanged
Себастьян Редл

3
Візьміть до уваги: ​​C # 6 дозволяє "авто-властивості лише для отримання", що в одному рядку забезпечує те, що робить мій приклад "А".
Джессі К. Слікер

6

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

public double Bar
{
    get { return _baz; }
    set { _bar = value; }
}

Я думаю, що така помилка могла трапитися досить легко і її було б досить важко помітити.

А якщо ви хочете послідовність, зробіть це інакше: змініть код, який використовує резервні поля в код, який використовує автоматичні властивості. Це особливо просто, якщо ви використовуєте такий інструмент рефакторингу, як ReSharper (і якщо ви не використовуєте щось подібне, я думаю, ви повинні почати).

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


Я насправді зробив це на кількох старих полях, коли рефакторинг коду ... це біль.
KChaloux

1

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

  1. Двигуни серіалізації під час запуску зберігають ім'я поданих у серіалізованому потоці. Ім'я поля резервного копіювання для автоматично реалізованої властивості (AIP) визначається компілятором, і воно може фактично змінювати ім'я цього поля резервного копіювання кожен раз, коли перекомпілювати код, відкидаючи можливість дезаріалізувати екземпляри будь-яких типів, що містять AIP. Тому не використовуйте AIP з будь-яким типом, який ви маєте намір серіалізувати чи десеріалізувати.

  2. Під час налагодження ви не можете поставити точку перерви методом get або set AIP, тому ви не зможете легко визначити, коли програма отримує або встановлює це властивість. Ви можете встановити точки перерви на точки вбивства, реалізовані вручну


3
# 1 - Більшість серіалізаторів за замовчуванням ігнорують приватні властивості / поля; Я ніколи не стикався з проблемами, які ви згадуєте. №2 - Це виправлено у VS2015 і його можна буде вирішити у VS2013. Дивіться цю статтю журналу Visual Studio .
Брайан

-3

Чи є вагомі причини віддати перевагу старішому, більш чіткому стилю перед новим, більш стислим?

Не зовсім. Хоча я б заперечував, що кожного разу, коли ви проходили подібний майно, вам слід було б просто використовувати публічне поле для початку.

Чи слід писати якісь нові класи, використовуючи стислий стиль, чи намагатись відповідати старішому коду за послідовністю? Чи достатньо в цьому випадку послідовності, щоб виправдати старіший формат?

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



@svick - Бах. Якщо ви не замислюєтесь про тип, різниці немає. Якщо ви публічно виставляєте тип як інтерфейс служби або бібліотеки, ви збираєтесь відкрити інтерфейс, який вимагає властивості в будь-якому випадку. ОП не робить жодної з цих речей.
Теластин

2
У цих обмежених випадках технічної причини немає . Не забувайте, що властивості поводяться по-різному в налагоджувачі, діаграмах класів, інтелісенсі, і саме тоді, коли ви думаєте, що не займаєтеся рефлексією, .NET Framework є. WinForms, WPF та декілька інших компонентів внутрішньо використовують відображення, і вони розглядають властивості окремо, тому поради щодо використання публічних полів коли-небудь будуть погано отримані багатьма розробниками на цьому сайті.
Кевін МакКормік

1
@KevinMcCormick і фреймворк добре поводиться (з того, що я розумію) з полями. Це не дуже важливо , так як є авто-властивості зараз, але велика проблема робить речі громадськості в першу чергу. Дуже багато людей вважають, що просто створення властивостей речі якось звільняє їх від "не робити публічні поля".
Теластин

2
Framework обробляє їх по-різному: спробуйте використовувати публічне поле в EF POCO, прив’язати його до DataGridView, використовувати PropertyGrid і т. Д. Я просто здійснив швидкий пошук у своєму декомпіляторі на Type.GetProperties / GetProperty, і Framework робить виклики до цього методу сотні разів, але не на GetField. Підсумок, вони різні, і рекомендація завжди використовувати властивості для публічних даних частково базується на цьому. Це не виключає використання полів ніколи, але цей випадок потребує виправдання. Однак ваш інший пункт, безумовно, правдивий, недбале оприлюднення публічних даних - це завжди погана ідея.
Кевін МакКормік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.