Ошибка компилятора CS0120 с текстом «для нестатического поля метода или свойства требуется ссылка на объект» возникает в момент сборки проекта, когда из статического контекста — например, из метода Main — идёт обращение к полю или методу класса без создания его экземпляра. Компилятор C# останавливает сборку и указывает строку, где имя члена класса использовано так, будто он статический, хотя объявлен обычным.

Эта ошибка — одна из самых частых у начинающих разработчиков на .NET, особенно в консольных приложениях, где точка входа static void Main() по определению статична. Разберём, почему она возникает, как её диагностировать и какие способы исправления подходят в разных ситуациях.

Что означает ошибка CS0120

В C# члены класса делятся на статические и нестатические (экземплярные). Статический член принадлежит самому классу и существует в единственном экземпляре на всё приложение. Нестатический член принадлежит конкретному объекту — и пока объект не создан через new, обращаться к его полям и методам не к чему.

Когда вы пишете MyClass.Counter = 5;, а поле Counter объявлено без модификатора static, компилятор не знает, к какому именно объекту относится присваивание. Объектов может быть тысяча — или ни одного. Поэтому он требует ссылку на объект: конкретную переменную, через которую станет ясно, с чьим полем работать.

Важно понимать: это ошибка времени компиляции, а не выполнения. Программа с таким кодом просто не соберётся, и исправлять её нужно в исходниках, а не в настройках проекта или среды.

Типичный код, вызывающий ошибку

Классический сценарий — обращение к экземплярному методу из статического Main:

class Program

{

int counter = 0;

void Increment()

{

counter++;

}

static void Main()

{

Increment(); // Ошибка CS0120

counter = 10; // Ошибка CS0120

}

}

Здесь и поле counter, и метод Increment() нестатические, а Main — статический по требованию платформы. Внутри статического метода нет неявного this, поэтому компилятор не может подставить ссылку на объект автоматически.

Похожая ситуация возникает и при обращении через имя класса из любого другого места: Program.Increment(); даст ту же ошибку, потому что синтаксис «класс.член» допустим только для статических членов.

📊 Где вы чаще всего встречаете ошибку CS0120?
В консольном приложении в методе Main
В ASP.NET при работе с контроллерами
В Unity-скриптах
В юнит-тестах

Способ 1: создать экземпляр класса

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

static void Main()

{

var program = new Program();

program.Increment();

program.counter = 10;

}

Обратите внимание: после создания экземпляра доступ к его членам идёт через переменную program, а не через имя класса. Каждый созданный объект хранит собственную копию нестатических полей — изменение counter у одного экземпляра не затронет другой.

☑️ Проверка перед исправлением CS0120

Выполнено: 0 / 5

Способ 2: сделать член статическим

Если поле или метод по смыслу относится ко всему классу, а не к отдельному объекту — например, глобальный счётчик или вспомогательная функция без состояния — добавьте модификатор static:

class Program

{

static int counter = 0;

static void Increment()

{

counter++;

}

}

Однако это решение с последствиями. Статическое поле одно на всё приложение, и к нему применяются ограничения:

  • 🔒 Статический метод не может обращаться к нестатическим членам того же класса — ошибка «переедет» внутрь него.
  • 🧵 При многопоточном доступе к разделяемому статическому состоянию потребуется синхронизация.
  • 🧪 Код с тяжёлой зависимостью от статики сложнее покрывать юнит-тестами и подменять зависимости.
  • ♻️ Статическое состояние живёт всё время работы приложения и не сбрасывается между логическими операциями.
⚠️ Внимание: механическое добавление static ко всем членам, на которые ругается компилятор, — распространённая ловушка новичков. Ошибка исчезнет, но архитектура превратится в набор глобальных переменных, что позже приведёт к трудноотлавливаемым багам.

Способ 3: обращение через другой объект или свойство

Часто CS0120 возникает не в Main, а при попытке достучаться до члена одного класса из другого. Например, когда форма пытается прочитать поле другой формы через имя класса: Form1.userName. Здесь нужна ссылка на уже существующий экземпляр — её передают через конструктор, параметр метода или публичное свойство.

class ReportPrinter

{

public void Print(Document doc)

{

Console.WriteLine(doc.Title); // доступ через параметр-ссылку

}

}

Ключевой вопрос при такой ошибке: «экземпляр какого класса уже существует и владеет нужными данными?». Ответ на него показывает, какую ссылку передать и куда.

💡

Если ошибка возникает в Unity при обращении к компоненту — проверьте, не пытаетесь ли вы вызвать метод через имя класса вместо ссылки, полученной через GetComponent или назначенной в инспекторе.

Сравнение подходов к исправлению

Выбор способа зависит от роли члена в архитектуре. Сводная таблица поможет сориентироваться:

ПодходКогда уместенГлавный риск
Создать экземпляр через newЧлен хранит состояние объектаЛишние объекты при неправильном времени жизни
Добавить staticОбщие утилиты, данные без состоянияГлобальное состояние, проблемы с потоками
Передать ссылку параметромВзаимодействие двух классовИзбыточная связанность классов
Внедрение зависимостей (DI)Сервисы в ASP.NET и крупных приложенияхУсложнение инфраструктуры для мелких задач
💡

CS0120 — не баг платформы, а защита компилятора: он требует явно указать, к какому объекту относится обращение. Правильное исправление — осознанный выбор между экземпляром и static, а не механическая правка.

Как быстро найти источник ошибки в проекте

В крупном решении ошибка CS0120 может сопровождаться десятками связанных сообщений. Действуйте системно:

  • 🔍 Откройте Список ошибок в Visual Studio и дважды кликните по первой записи CS0120 — среда перенесёт курсор к проблемной строке.
  • 🧭 Исправляйте ошибки сверху вниз: часто одна первичная проблема порождает цепочку последующих.
  • 🏷️ Наведите курсор на имя члена — всплывающая подсказка покажет, объявлен он как static или нет.
  • 🧱 После каждой правки выполняйте пересборку через Build → Rebuild Solution, чтобы видеть актуальный список ошибок.

Если ошибка появилась после рефакторинга — например, вы сделали метод статическим — проверьте все места его вызова через поиск по ссылкам (Find All References). Нестатические зависимости внутри такого метода придётся либо тоже делать статическими, либо получать через параметры.

Почему Main обязан быть статическим

Точка входа вызывается средой CLR до того, как создан какой-либо объект приложения. Поскольку экземпляра ещё не существует, метод Main объявляется static — иначе рантайм просто не смог бы его вызвать. Поэтому любой код внутри Main стартует в статическом контексте, и первым шагом обычно создают объект: new Program().Run().

Связанные ошибки и чем они отличаются

CS0120 часто путают с другими сообщениями компилятора. Ошибка CS0176 звучит наоборот: «для члена требуется ссылка на объект, так как он не является статическим» — она возникает при обращении через имя класса к экземплярному члену. По сути это та же проблема, зафиксированная в другом синтаксисе.

Отдельно стоит NullReferenceException — ошибка уже времени выполнения, когда ссылка на объект есть, но равна null. Если вы исправили CS0120, создав переменную, но забыли присвоить ей new ..., программа соберётся и упадёт именно с этим исключением. Переменная-ссылка без инициализации не равна созданному объекту — это принципиально разные состояния.

⚠️ Внимание: если после исправления CS0120 приложение падает с NullReferenceException, проверьте каждую переменную, через которую идёт обращение к членам, — все они должны быть проинициализированы до первого использования.

FAQ: частые вопросы об ошибке CS0120

Почему нельзя просто обратиться к полю через имя класса?

Потому что нестатическое поле существует только внутри конкретного объекта. Имя класса — это описание «чертёж», а не сам объект. Синтаксис Класс.Поле зарезервирован для статических членов, общих для всех экземпляров.

Ошибка возникает в Unity при вызове метода другого скрипта. Что делать?

Получите ссылку на экземпляр компонента: через GetComponent<Тип>(), публичное поле, назначенное в инспекторе, или FindObjectOfType. Вызов метода через имя класса скрипта без ссылки даст CS0120.

Стоит ли делать все поля статическими, чтобы ошибка не появлялась?

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

Может ли CS0120 появиться внутри свойства или конструктора?

Да — если свойство или конструктор объявлены статическими и пытаются обратиться к нестатическим членам. Статический конструктор, например, может инициализировать только статические поля класса.

Чем CS0120 отличается от NullReferenceException?

CS0120 — ошибка компиляции: ссылки на объект нет в принципе, код не собирается. NullReferenceException — ошибка выполнения: ссылка объявлена, но равна null в момент обращения. Первая лечится правкой кода, вторая — корректной инициализацией.