Статические члены
В углу чертежа архитектор ведёт счёт: сколько домов по нему уже построено. Это число не относится ни к одному дому. У красного дома нет своего «построено два», и у синего нет. Оно одно на весь чертёж, и после каждой новой стройки его увеличивают на единицу.
До сих пор у каждого объекта были свои поля и свойства: свой цвет, свои этажи. Но иногда данные нужны одни на весь класс. Для этого есть слово static:
var a = new House("red");
var b = new House("blue");
Console.WriteLine(House.Count); // 2
class House
{
public static int Count { get; private set; }
public string Color { get; }
public House(string color)
{
Color = color;
Count++;
}
}Давайте разберём программу:
public static int Count { get; private set; }— статическое свойство:Countодин на весь классHouse, а не по одному в каждом доме.public string Color { get; }— обычное свойство: у каждого дома свой цвет.- Каждый вызов конструктора выполняет
Count++и увеличивает тот же самый счётчик. House.Countчитают через имя класса, а не через дом, и строка печатает2.
Статический член — член, который принадлежит самому классу, а не его объектам. Обычные члены, как Color, есть у каждого объекта свои.
Через имя класса
Статический член существует, даже когда объектов нет совсем: до первого new выражение House.Count равно 0. Поэтому к нему обращаются через имя класса. Строка a.Count не скомпилируется: ошибка CS0176, компилятор просит написать имя типа.
Константа const тоже принадлежит типу, а не объекту. Поэтому вы пишете int.MaxValue: эта константа одна для всех чисел int.
Здесь чертёж и класс расходятся. Построенный дом не может ничего дописать на чертеже, а объект может менять статический член своего класса. Именно так конструктор каждого нового дома увеличивает Count.
Статические методы
Метод тоже бывает статическим. Такой метод не привязан ни к одному объекту, поэтому его вызывают через имя класса:
Console.WriteLine(House.Height(5)); // 15
class House
{
public static int Height(int floors) => floors * 3;
}Чтобы узнать высоту пятиэтажного дома по три метра на этаж, дом строить не нужно: хватает числа этажей. Поэтому Height — статический метод.
Статическими методами вы пользуетесь с первой программы курса:
Console.WriteLine— объектConsoleникто не создаёт;int.Parseиint.TryParse— их вызывают через имя типаint;Array.Sort— его вызывают через имя классаArray, а массив передают аргументом.
И static void Main() из темы о первой программе статический по той же причине: среда выполнения вызывает Main, не создавая объект класса Program.
Статический или обычный
Об этом часто спрашивают на собеседовании: «Чем статический член отличается от обычного?» Ответ из трёх частей:
- статический член один на весь класс, а обычный есть у каждого объекта свой;
- к статическому обращаются через имя класса, к обычному — через объект;
- статический метод не может обратиться к обычным членам напрямую: у него нет
this, нет своего объекта.
Член делают статическим, когда ему не нужны данные конкретного объекта: общий счётчик, расчёт только по параметрам метода.
Частая ошибка
Статический метод читает обычное свойство:
var a = new House("red");
Console.WriteLine(House.Describe());
class House
{
public string Color { get; }
public House(string color) => Color = color;
public static string Describe() => "Color: " + Color; // ✗
}error CS0120: An object reference is required for the non-static field, method, or property 'House.Color'Программа не компилируется. Статический метод вызывают через класс, без дома, поэтому непонятно, чей цвет он должен прочитать. Сообщение так и говорит: чтобы обратиться к обычному члену House.Color, нужна ссылка на объект. Уберите static и вызывайте метод через дом: a.Describe() вместо House.Describe(). Тогда он прочитает цвет того дома, для которого его вызвали.
Главное
- Статический член, объявленный со словом
static, один на весь класс; обычные члены есть у каждого объекта свои. - К статическому члену обращаются через имя класса:
House.Count,int.Parse; через объект — не компилируется. - Статический метод работает без объекта, поэтому к обычным полям и свойствам напрямую обратиться не может.
Console.WriteLine,int.Parseиstatic void Main()— статические методы.