Что такое модификатор static в C#?

Ответ

Модификатор static в C# означает, что член (поле, свойство, метод, событие) или весь класс принадлежит самому типу, а не конкретному экземпляру (объекту) этого типа. Это позволяет использовать член без создания экземпляра класса.

Основные случаи использования:

  1. Статические члены класса:

    • Статические поля/свойства: Существуют в единственном экземпляре для всего приложения, общие для всех объектов класса. Часто используются для констант, настроек или кэшей.
    • Статические методы: Могут быть вызваны напрямую через имя класса. Не имеют доступа к нестатическим полям и методам, так как для них не существует контекста this.

      
      public class MathHelper
      {
      // Статическое поле-счётчик
      public static int CallCount { get; private set; } = 0;
      
      // Статический метод
      public static int Add(int a, int b)
      {
          CallCount++; // Увеличиваем общий счётчик
          return a + b;
      }
      }

    // Использование: int sum = MathHelper.Add(5, 3); // Вызов без создания объекта Console.WriteLine(MathHelper.CallCount); // 1

  2. Статический класс:

    • Нельзя создать его экземпляр с помощью new.
    • Может содержать только статические члены.
    • Часто используется для утилитарных классов (например, Math, Console).
      
      public static class Logger
      {
      public static void Log(string message)
      {
          Console.WriteLine($"[{DateTime.Now}] {message}");
      }
      }

    // Использование: Logger.Log("Application started");

Важно: Из-за общего состояния статические поля требуют осторожности в многопоточных сценариях, так как могут стать источником состояния гонки (race condition).

Ответ 18+ 🔞

Давай разберём эту штуку с static в C#, а то народ часто путается, как будто им в детстве книжку про ООП на голову уронили.

Смотри, представь себе класс — это как чертёж дома. Обычные поля и методы — это мебель и жильцы внутри конкретного дома. А static — это типа городская инфраструктура: одна на всех, общая. Фонарь на улице, он не в твоей квартире стоит, он один на весь район, и чтобы им пользоваться, тебе не нужно заходить в какой-то конкретный дом.

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

Где это применяется:

  1. Статические поля/свойства (общее состояние). Это как общий счётчик, который видят все.

    public class ЗаводИгрушек
    {
        // Это общий счётчик для ВСЕХ заводов, если бы они были.
        // Но так как класс нестатический, а поле статическое — счётчик всё равно один на всю программу.
        public static int ВсегоИгрушекСделано = 0;
        public string НазваниеЗавода;
    
        public void ВыпуститьИгрушку()
        {
            ВсегоИгрушекСделано++; // Увеличиваем ГЛОБАЛЬНЫЙ счётчик
            Console.WriteLine($"Завод '{НазваниеЗавода}' сделал игрушку. Всего уже: {ВсегоИгрушекСделано}");
        }
    }
    
    // Использование:
    var завод1 = new ЗаводИгрушек { НазваниеЗавода = "Весёлый молочник" };
    var завод2 = new ЗаводИгрушек { НазваниеЗавода = "Грустный пекарь" };
    
    завод1.ВыпуститьИгрушку(); // Всего уже: 1
    завод2.ВыпуститьИгрушку(); // Всего уже: 2
    // Оба кадрика тыкали в одно и то же поле!

    Вот тут и кроется опасность, ёпта. В многопоточке начинается пиздец — все лезут в одну кучу, а результат получается непредсказуемый. Нужны замки (lock) или другие штуки, чтобы не было гонки.

  2. Статические методы (утилиты). Самый частый случай. Вызываются от имени класса. Внутри себя они не имеют доступа к нестатическим полям объекта, потому что у них нет this — не к кому обращаться, объекта-то может и не быть!

    public class Калькулятор
    {
        // Нестатическое поле — у каждого калькулятора своё.
        public string Цвет;
    
        // Статический метод — общий инструмент.
        public static int Сложить(int a, int b)
        {
            // Console.WriteLine(Цвет); // ОШИБКА! Какой цвет? Чей цвет? Их много!
            return a + b;
        }
    
        // Нестатический метод — работает с конкретным экземпляром.
        public void Покрасить(string новыйЦвет)
        {
            this.Цвет = новыйЦвет; // А вот тут this есть — это цвет ЭТОГО калькулятора.
        }
    }
    
    // Использование:
    int результат = Калькулятор.Сложить(2, 2); // Работает, объект не нужен.
    // Калькулятор.Покрасить("красный"); // ОШИБКА! Нестатический метод — нужен объект.
    
    var мойКалькулятор = new Калькулятор();
    мойКалькулятор.Покрасить("синий"); // А теперь ок.
  3. Статический класс. Это уже совсем крутая тема. Такой класс — просто контейнер для статических методов и полей. Создать его экземпляр нельзя в принципе. Он как набор инструментов, лежащих на полке, а не станок, который нужно включать.

    public static class Логгер // Ключевое слово static тут
    {
        private static string _путьКФайлу = "log.txt";
    
        public static void Записать(string сообщение)
        {
            File.AppendAllText(_путьКФайлу, $"{DateTime.Now}: {сообщение}{Environment.NewLine}");
        }
    }
    
    // Использование:
    Логгер.Записать("Программа стартанула, всё по плану.");
    // new Логger(); // ОШИБКА! Статический класс нельзя инстанцировать, нахуй оно надо?

Итог:
static — это про общность и независимость от экземпляра. Используй для всего, что должно быть в одном экземпляре на весь тип (или приложение): утилиты, хелперы, фабрики, глобальные настройки (аккуратно!), кэши.
Но помни про подводные камни в многопоточности и не злоупотребляй глобальным состоянием, а то получится спагетти-код, где всё зависит от всего, и отлаживать это — просто ебать колотить.