JavaRush /Курси /C# SELF /Властивості (Properties) у C#

Властивості (Properties) у C#

C# SELF
Рівень 17 , Лекція 1
Відкрита

1. Вступ

Почнімо з проблем, що виникають під час прямого використання полів. Якщо ви оголосите поле як public, його можна буде змінювати одразу й напряму з будь-якої частини програми:

public class Dog
{
    public string Name;
}

Dog dog = new Dog();
dog.Name = ""; // O_o ... це як "імʼя собаки = порожній рядок"!

Користувач може присвоїти полю Name будь‑які, навіть абсурдні, значення: порожній рядок, надто довге імʼя або взагалі null. Це все одно, що хтось збирав би вашу нову шафу IKEA, а ви дали б йому повний доступ до деревообробного цеху.

Памʼятайте: інкапсуляція — це коли обʼєкт сам контролює свої дані. Ми не довіряємо внутрішнє кожному охочому, а даємо спеціальні «дверцята» — властивості (Properties), через які й відбувається доступ до поля — із можливістю перевірки, журналювання, модифікації чи інших реакцій на зміну значення.

2. Визначення і синтаксис

Властивість — це особливий член класу, який виглядає майже як поле, але насправді всередині є парою спеціальних методів: getter (отримати значення) і setter (встановити значення). За допомогою властивості ми можемо:

  • Дозволити або заборонити читання чи запис даних;
  • Додати валідацію або логіку під час доступу до даних;
  • Сховати внутрішнє поле й навіть зберігати значення деінде.

Властивість оголошується дуже схоже на поле, тільки з фігурними дужками і ключовими словами get і set усередині.


[модифікатор_доступу] тип ІмʼяВластивості
{
    get { ... }
    set { ... }
}
Шаблон оголошення властивості

Ось приклад для нашого класу Dog:

public class Dog
{
    private string _name; // внутрішнє поле (private!)

    public string Name
    {
        get { return _name; }  // "геттер": отримати імʼя
        set { _name = value; } // "сеттер": присвоїти імʼя
    }
}

Примітка: підкреслення зазвичай використовують для приватних полів (_name). Це поширений стиль у C#.

3. Механіка роботи властивості

Властивість — це свого роду «охоронець», який стоїть між внутрішніми даними обʼєкта і зовнішнім світом. Приклад:

Dog dog = new Dog();
dog.Name = "Рижик";
Console.WriteLine(dog.Name);

Пояснення:

  • Коли виконання програми дістається рядка dog.Name = "Рижик";, викликається set-метод властивості, і ви можете додати туди будь‑яку потрібну перевірку (наприклад, переконатися, що імʼя не порожнє).
  • У момент Console.WriteLine(dog.Name); викликається get-метод, який просто повертає поточне значення або, за потреби, обчислює його динамічно.

Виглядає, наче це звичайне поле, але насправді тут усе під контролем!

4. Чому властивості — це «найкраща практика»

У більшості випадків ми не надаємо прямого доступу до внутрішніх полів обʼєкта. Навіть якщо зараз перевірки не потрібні, звичка огортати дані у властивості дуже виручає, коли правила гри зміняться.

Приклад перевірки під час присвоєння:


public class Dog
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentException("Імʼя собаки не може бути порожнім!");
            }
            _name = value;
        }
    }
}

Тепер таке присвоєння:

dog.Name = ""; // Буде викинуто виняток!

… захищає наш обʼєкт від абсурдних значень.

5. Властивості: лише для читання, лише для запису і звичайні

Іноді варто дозволяти лише читання значення (наприклад, у собаки є рік народження — його не змінюють) або, навпаки, лише встановлення (зустрічається рідко, але інколи це потрібно).

  • Лише для читання: пишемо тільки get, прибираємо set.
  • Лише для запису: пишемо тільки set, прибираємо get.

Приклади:

public class Dog
{
    private int _birthYear = 2018;

    // Лише для читання
    public int BirthYear
    {
        get { return _birthYear; }
    }

    // Лише для запису (зустрічається рідко)
    public string Secret
    {
        set { /* робимо щось з value */ }
    }
}

6. Властивості проти полів

Поле Властивість
Синтаксис
public string Name;
public string Name { get; set; }
Доступ Прямий Через get/set
Валідація Немає Можна додати у set/get
Розширюваність Немає Можна модифікувати в будь-який момент
IDE-інтеграція Видно як поля Видно як властивості (важливо для фреймворків)

Ілюстрація: Робота властивості

sequenceDiagram
participant User as Користувач об'єкта
participant Dog as Об'єкт Dog
participant Field as Приватне поле _name

User->>Dog: dog.Name = "Рижик"
Dog->>Dog: set Name("Рижик")
Dog->>Field: _name = "Рижик"

User->>Dog: print(dog.Name)
Dog->>Dog: get Name()
Dog->>Field: читає _name
Dog->>User: повертає "Рижик"

7. Типові помилки і нюанси

Розберімося, де тут можуть підстерігати пастки.

Типова помилка — плутати поля й властивості та випадково відкривати приватні дані назовні:

public string name; // Це поле! Його видно всюди, небезпечно!

Краще так:

private string _name;
public string Name
{
    get { return _name; }
    set { _name = value; }
}

Статичні властивості існують, щоб зберігати спільні для всіх обʼєктів значення. Але використовуйте їх обережно.

Цікаво: якщо у властивості є лише get і немає set, її неможливо змінити — це називається незмінна властивість (immutable property) і активно використовується в сучасних підходах до проєктування (ми детально повернемося до цього в лекціях про record і незмінність даних).

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ