C# Academy · Урок

Статические и экземплярные элементы

Определяйте, когда уместно использовать статическое состояние.

Урок 4 из 413 шагов

«Статические и экземплярные элементы» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Проектное решение

Выбор между static и instance — это проектное решение. Главный вопрос: зависит ли поведение от состояния отдельного объекта или только от входных данных?

using System;

class Program
{
    // Depends only on inputs -> good static method
    static int Max(int a, int b) => a > b ? a : b;

    static void Main()
    {
        Console.WriteLine(Max(3, 8));
    }
}

Используйте статический подход для логики без состояния

Если методу не нужны поля экземпляра и он лишь преобразует входные данные, сделайте его static. Отличные примеры — математические вспомогательные методы и средства форматирования.

using System;

static class Convert2
{
    public static double MilesToKm(double miles) => miles * 1.60934;
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Convert2.MilesToKm(10).ToString("0.0") + " km");
    }
}

Используйте экземпляр для состояния

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

using System;

class Counter
{
    private int _count;
    public void Increment() => _count++;
    public int Value => _count;
}

class Program
{
    static void Main()
    {
        var a = new Counter();
        var b = new Counter();
        a.Increment();
        a.Increment();
        b.Increment();
        Console.WriteLine("a=" + a.Value + ", b=" + b.Value);
    }
}

Общее состояние — глобальное состояние

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

using System;

class BadCart
{
    public static int Items;   // shared by EVERYONE -> usually wrong for a cart
}

class Program
{
    static void Main()
    {
        BadCart.Items++;
        BadCart.Items++;
        Console.WriteLine("All carts share: " + BadCart.Items);
    }
}

Тестируемость

Чистые статические методы легко тестировать: одинаковые входные данные дают одинаковой результат. Однако изменяемое статическое состояние сохраняется между тестами и делает их хрупкими.

using System;

static class Calc
{
    public static int Add(int a, int b) => a + b;   // trivially testable
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Calc.Add(2, 2) == 4 ? "pass" : "fail");
    }
}

Статические фабричные методы

Статические фабричные методы — удобный способ создавать настроенные экземпляры с понятным именем.

using System;

class Color
{
    public int R, G, B;
    private Color(int r, int g, int b) { R = r; G = g; B = b; }

    public static Color Red() => new Color(255, 0, 0);
    public static Color White() => new Color(255, 255, 255);
}

class Program
{
    static void Main()
    {
        var c = Color.Red();
        Console.WriteLine(c.R + "," + c.G + "," + c.B);
    }
}

Не используйте статический подход только ради отказа от создания объектов

Не делайте всё статическим только для того, чтобы не создавать объекты. Если тип описывает сущность с состоянием, экземпляры сохраняют это состояние изолированным и безопасным.

using System;

class Player
{
    public string Name;
    public int Health = 100;
    public void TakeDamage(int d) => Health -= d;
}

class Program
{
    static void Main()
    {
        var p1 = new Player { Name = "A" };
        var p2 = new Player { Name = "B" };
        p1.TakeDamage(30);
        Console.WriteLine(p1.Name + ": " + p1.Health + ", " + p2.Name + ": " + p2.Health);
    }
}

Уместное сочетание обоих подходов

Во многих классах статические члены используют для общих констант или счётчиков, а члены экземпляра — для данных отдельных объектов. Такое сочетание вполне соответствует принятому стилю.

using System;

class Invoice
{
    private static int _seq = 1000;
    public readonly int Number;
    public decimal Amount;

    public Invoice(decimal amount)
    {
        Number = _seq++;
        Amount = amount;
    }
}

class Program
{
    static void Main()
    {
        var i1 = new Invoice(50m);
        var i2 = new Invoice(75m);
        Console.WriteLine(i1.Number + " / " + i2.Number);
    }
}

Проблема параллельного доступа

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

using System;

class SafeCalc
{
    // No shared mutable state -> naturally thread-safe
    public static long Factorial(int n)
    {
        long result = 1;
        for (int i = 2; i <= n; i++) result *= i;
        return result;
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine(SafeCalc.Factorial(5));
    }
}

Простое практическое правило

Static = поведение, принадлежащее типу и не использующее состояние отдельных объектов. Instance = поведение, которое читает или изменяет конкретный объект. Если сомневаетесь, выбирайте экземпляр для всего, что связано с состоянием.

using System;

class Temperature
{
    public double Celsius;                                  // instance state
    public static double ToF(double c) => c * 9 / 5 + 32;   // stateless helper
}

class Program
{
    static void Main()
    {
        var t = new Temperature { Celsius = 30 };
        Console.WriteLine(Temperature.ToF(t.Celsius));
    }
}

Собираем всё вместе

Хорошее проектирование отделяет вспомогательные методы без состояния (статические) от моделей с состоянием (экземпляры), сводя общее изменяемое состояние к осознанному минимуму.

using System;

static class TaxRules
{
    public static decimal Apply(decimal amount, decimal rate) => amount + amount * rate;
}

class Sale
{
    public decimal Subtotal;
    public decimal Total(decimal rate) => TaxRules.Apply(Subtotal, rate);
}

class Program
{
    static void Main()
    {
        var s = new Sale { Subtotal = 100m };
        Console.WriteLine(s.Total(0.2m));
    }
}

Быстрая проверка

Проверьте, насколько хорошо вы понимаете различия между статическим подходом и экземплярами.

Итоги

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

using System;

static class Util { public static int Sq(int n) => n * n; }

class Box { public int Size; public int Area() => Util.Sq(Size); }

class Program
{
    static void Main()
    {
        var box = new Box { Size = 4 };
        Console.WriteLine(box.Area());
    }
}
Можно начать бесплатно

Изучай C# с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
93
Уроки
346

Часто задаваемые вопросы

Урок «Статические и экземплярные элементы» бесплатный?

Да — полный текст урока «Статические и экземплярные элементы» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Статические и экземплярные элементы»?

Определяйте, когда уместно использовать статическое состояние. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Статические и экземплярные элементы»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Статические методы и поля
  2. Статические классы для вспомогательных средств
  3. Константы и поля readonly
  4. Статические и экземплярные элементы
← Назад к C# Academy