Кроме обычных полей, методов, свойств классы и структуры могут иметь статические поля, методы, свойства. Статические поля, методы, свойства относятся ко всему классу/всей структуре и для обращения к подобным членам необязательно создавать экземпляр класса / структуры.
Статические поля хранят состояние всего класса / структуры. Статическое поле определяется как и обычное, только перед типом поля указывается ключевое слово static. Например, рассмотрим класс Person, который представляет человека:
Person bob = new(68); bob.СheckAge(); // Уже на пенсии Person tom = new(37); tom.СheckAge(); // Сколько лет осталось до пенсии: 28 // получение статического поля Console.WriteLine(Person.retirementAge); // 65 // изменение статического поля Person.retirementAge = 67; class Person { int age; public static int retirementAge = 65; public Person(int age) { this.age = age; } public void СheckAge() { if (age >= retirementAge) Console.WriteLine("Уже на пенсии"); else Console.WriteLine($"Сколько лет осталось до пенсии: {retirementAge - age}"); } }
В данном случае класс Person имеет два поля: age
(хранит возраст человека) и retirementAge
(хранит пенсионный возраст).
Однако поле retirementAge
является статическим. Оно относится не к конкретному человеку, а ко всем людям. (В данном случае для
упрощения пренебрежем тем фактом, что в зависимости от пола и профессии пенсионный возраст может отличаться.) Таким образом, поле retirementAge относится
не к отдельную объекту и хранит значение НЕ отдельного объекта класса Person, а относится ко всему классу Person и хранит общее значение для всего класса.
Причем в самом классе мы можем использовать это поле как и любые другие. Так, в методе СheckAge()
, который поверяет пенсионный статус человека,
для проверки используем это поле:
if (age >= retirementAge)
Но если мы хотим обратиться к этому полю вне своего класса, то мы можем обращаться к этому полю по имени класса:
Console.WriteLine(Person.retirementAge); Person.retirementAge = 67;
На уровне памяти для статических полей будет создаваться участок в памяти, который будет общим для всех объектов класса.
При этом память для статических переменных выделяется даже в том случае, если не создано ни одного объекта этого класса.
Подобным образом мы можем создавать и использовать статические свойства:
Person bob = new(68); bob.СheckAge(); Console.WriteLine(Person.RetirementAge); // 65 class Person { int age; static int retirementAge = 65; public static int RetirementAge { get { return retirementAge; } set { if (value > 1 && value < 100) retirementAge = value; } } public Person(int age) { this.age = age; } public void СheckAge() { if (age >= retirementAge) Console.WriteLine("Уже на пенсии"); else Console.WriteLine($"Сколько лет осталось до пенсии: {retirementAge - age}") ; } }
В данном случае доступ к статической переменной retirementAge опосредуется с помощью статического свойства RetirementAge
.
Таким образом, переменные и свойства, которые хранят состояние, общее для всех объектов класса / структуры, следует определять как статические.
Нередко статические поля и свойства применяются для хранения счетчиков. Например, мы хотим иметь счетчик, который позволял бы узнать, сколько объектов Person создано:
var tom = new Person(); var bob = new Person(); var sam = new Person(); Console.WriteLine(Person.Counter); // 3 class Person { static int counter = 0; public static int Counter => counter; public Person() { counter++; } }
В данном случае в классе Person счетчик хранится в приватной переменной counter, значение которой увеличивается на единицу при создании объекта в конструкторе. А с помощью статического свойства Counter, которое доступно только для чтения, мы можем получить значение счетчика.
Статические методы определяют общее для всех объектов поведение, которое не зависит от конкретного объекта. Для обращения к статическим методам также применяется имя класса / структуры:
Person bob = new(68); Person.CheckRetirementStatus(bob); class Person { public int Age { get; set; } static int retirementAge = 65; public Person(int age) => Age = age; public static void CheckRetirementStatus(Person person) { if (person.Age >= retirementAge) Console.WriteLine("Уже на пенсии"); else Console.WriteLine($"Сколько лет осталось до пенсии: {retirementAge - person.Age}") ; } }
В данном случае в классе Person определен статический метод CheckRetirementStatus()
, который в качестве параметра принимает объект Person и проверяет его пенсионный статус.
Следует учитывать, что статические методы могут обращаться только к статическим членам класса. Обращаться к нестатическим методам, полям, свойствам внутри статического метода мы не можем.
Кроме обычных конструкторов у класса также могут быть статические конструкторы. Статические конструкторы имеют следующие отличительные черты:
Статические конструкторы не должны иметь модификатор доступа и не принимают параметров
Как и в статических методах, в статических конструкторах нельзя использовать ключевое слово this для ссылки на текущий объект класса и можно обращаться только к статическим членам класса
Статические конструкторы нельзя вызвать в программе вручную. Они выполняются автоматически при самом первом создании объекта данного класса или при первом обращении к его статическим членам (если таковые имеются)
Статические конструкторы обычно используются для инициализации статических данных, либо же выполняют действия, которые требуется выполнить только один раз
Определим статический конструктор:
Console.WriteLine(Person.RetirementAge); class Person { static int retirementAge; public static int RetirementAge => retirementAge; static Person() { if (DateTime.Now.Year == 2022) retirementAge = 65; else retirementAge = 67; } }
В данном случае с помощью встроенной структуры DateTime получаем текущий год. Для этого используется свойство DateTime.Now.Year
.
если он равен 2022, устанавливаем один пенсионный возраст. При другом значении текущего года устанавливается другое значение пенсионного возраста.
Статические классы объявляются с модификатором static и могут содержать только статические поля, свойства и методы. Например, определим класс, который выполняет ряд арифметических операций:
Console.WriteLine(Operations.Add(5, 4)); // 9 Console.WriteLine(Operations.Subtract(5, 4)); // 1 Console.WriteLine(Operations.Multiply(5, 4)); // 20 static class Operations { public static int Add(int x, int y) => x + y; public static int Subtract(int x, int y) => x - y; public static int Multiply(int x, int y) => x * y; }