Защо капсулация
До сега правихме полетата public — всеки можеше да ги чете и да им присвоява каквото и да е. Това е удобно, но опасно:
class BankAccount
{
public double Balance;
}
var a = new BankAccount();
a.Balance = -1_000_000; // 🙃 нищо не ни пречиКапсулацията крие вътрешното състояние и позволява достъп само през контролирани методи/свойства. Така можем да валидираме всяка промяна.
Модификатори на достъп
| Модификатор | Достъп от |
|---|---|
| public | Навсякъде |
| private | Само вътре в самия клас (по подразбиране за полета) |
| protected | В класа и в наследниците му |
| internal | В същия assembly (проект) |
| protected internal | internal ИЛИ protected |
Ключово
Правило: полетата винаги private, достъпът — през свойства.
Свойства (properties)
Свойството изглежда като поле, но всъщност е чифт get/set методи:
class BankAccount
{
private double balance; // скрито поле
public double Balance
{
get { return balance; }
set
{
if (value < 0)
throw new ArgumentException("Балансът не може да е отрицателен.");
balance = value;
}
}
}
var a = new BankAccount();
a.Balance = 500; // влиза през set — валидира
Console.WriteLine(a.Balance); // вика getAuto-properties — съкратената форма
Когато няма специална логика, C# ти спестява boilerplate-а:
class Student
{
public string Name { get; set; }
public double Grade { get; set; }
}Зад кулисите компилаторът създава скрито поле и тривиалните get/set.
Само за четене (read-only) свойства
class Person
{
public string Name { get; }
public int Age { get; private set; } // могат да присвояват само методите на класа
public Person(string name, int age)
{
Name = name;
Age = age;
}
public void Birthday() => Age++;
}Изчислими свойства
class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
public double Area => Width * Height; // няма set — изчислява се при всяко четене
}Валидация в setter
class Student
{
private double grade;
public double Grade
{
get => grade;
set
{
if (value < 2 || value > 6)
throw new ArgumentOutOfRangeException(
nameof(value), "Оценка трябва да е между 2 и 6.");
grade = value;
}
}
}Сега никой не може да присвои невалидна стойност — нито отвън, нито вътре в други методи на класа. Базата винаги остава консистентна.
Принципи за добър дизайн
- Полетата винаги
private; достъпът — през свойства. - Колкото по-малко публично, толкова по-добре. Лесно да добавиш достъп, трудно да отнемеш.
- Валидация в setter-а — едно място, винаги работи.
- Помисли: какво може да си позволи външният свят, без да повреди обекта?
Инкапсулация + неизменяемост
За още по-голяма сигурност — направи обекта неизменяем: всички свойства { get; }, конструкторът ги присвоява веднъж. След това няма как да се промени. Това е чест подход за данни-обекти (DTO-та, value objects).
Какво трябва да запомниш
- Капсулация = крием вътрешното, излагаме само нужното.
- Полетата
private; достъпът през свойства. { get; set; }= auto-property;{ get; }= read-only.- Setter-ът е мястото за валидация.
- Принцип: излагай минимума, валидирай всичко.