Course program← C#: Базовый курс
1Знакомство с C# и .NET
2Данные и типы
3Ветвления и циклы
4Методы и ошибки
5Коллекции и строки
6Классы и объекты

Класс, поля, конструктор

This lesson is not translated yet – the Russian original is below.

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

Класс – это описание, объект – экземпляр

Класс похож на чертёж. На чертеже указано, из чего состоит изделие и что оно умеет, но сам чертёж никуда не поедет. Ездят машины, собранные по нему, – и каждая своя: разного цвета, с разным пробегом.

Класс – описание типа: какие данные у него есть и что с ними можно делать. Объект (экземпляр) – конкретная сущность в памяти, созданная по этому описанию.

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

Самый простой класс

public class Book
{
    public string Title;
    public string Author;
    public int Year;
}

Внутри – поля: переменные, принадлежащие объекту. У каждого экземпляра они свои.

Создание объекта и работа с ним:

Book book = new Book();

book.Title = "Война и мир";
book.Author = "Толстой";

Console.WriteLine(book.Title);

Оператор new выделяет память под объект и возвращает ссылку на него. Класс – ссылочный тип, со всеми следствиями из урока про значимые и ссылочные типы: присваивание копирует ссылку, а не объект.

Конструктор

Создавать объект пустым, а потом заполнять поля по одному – плохо: между new и последним присваиванием объект находится в недоделанном состоянии. Конструктор решает это:

public class Book
{
    public string Title;
    public string Author;

    public Book(string title, string author)
    {
        Title = title;
        Author = author;
    }
}

Теперь книга не может появиться без названия и автора:

var book = new Book("Война и мир", "Толстой");

У конструктора две особенности: он называется точно так же, как класс, и не имеет типа возврата – даже void не пишут.

Пока своего конструктора нет, компилятор подставляет пустой. Как только вы объявили конструктор с параметрами, подставленный исчезает – и new Book() перестаёт собираться. Если нужны оба варианта, объявите оба явно: это обычная перегрузка.

Несколько конструкторов

Перегрузка работает и здесь, а чтобы не дублировать код, один конструктор вызывает другой через this:

public Book(string title, string author) : this(title, author, DateTime.Now.Year)
{
}

public Book(string title, string author, int year)
{
    Title = title;
    Author = author;
    Year = year;
}

Запись : this(...) означает «сначала выполни тот конструктор, потом мой». Заполнение полей остаётся в одном месте.

Методы

Класс хранит не только данные, но и действия над ними:

public class Book
{
    public string Title;
    public string Author;
    public int Year;

    public string GetDescription()
    {
        return $"{Title} – {Author}, {Year}";
    }

    public bool IsOlderThan(int year)
    {
        return Year < year;
    }
}

Внутри методов класса поля доступны просто по имени – объект, к которому относится вызов, подставляется автоматически:

var book = new Book("Война и мир", "Толстой", 1869);

Console.WriteLine(book.GetDescription());
Console.WriteLine(book.IsOlderThan(1900));    // True

Разница со static-методами, которыми мы пользовались весь курс, теперь видна: GetDescription работает с данными конкретного объекта, поэтому вызывается через него. Метод без static вызвать без объекта нельзя – ему не над чем работать.

this

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

public class Book
{
    private string title;

    public Book(string title)
    {
        this.title = title;    // слева поле, справа параметр
    }
}

Именно поэтому приватные поля и принято называть с подчёркиванием: при имени _title совпадения не возникает и this не требуется.

private: что скрыть

По умолчанию член класса виден только внутри самого класса. Слово public открывает его наружу:

public class BankAccount
{
    private decimal _balance;

    public void Deposit(decimal amount)
    {
        if (amount <= 0)
        {
            throw new ArgumentException("Сумма должна быть положительной");
        }

        _balance += amount;
    }

    public decimal GetBalance() => _balance;
}

Поле _balance закрыто, и изменить его извне напрямую нельзя – только через Deposit, где стоит проверка. Будь оно public, любой код мог бы записать туда отрицательное число, и никакая проверка бы не помогла.

Это и называется инкапсуляцией: класс сам отвечает за корректность своих данных, а не надеется, что все вокруг будут аккуратны.

Соглашение об именах: приватные поля пишут с подчёркиванием и маленькой буквы (_balance), всё публичное – с большой (Deposit, Title). По одному взгляду на имя видно, откуда оно доступно.

Где объявлять класс

Класс – это отдельный тип, и его принято класть в отдельный файл с тем же именем: Book.cs для класса Book. Технически можно объявить несколько классов в одном файле, но так не делают: искать потом неудобно.

При инструкциях верхнего уровня классы объявляются после основного кода – по тому же правилу, что и методы.