Компилятор C# выдаёт ошибку CS0120 с текстом «Для нестатического поля, метода или свойства требуется ссылка на объект» в тот момент, когда код обращается к члену класса через имя самого класса, а не через созданный экземпляр. Типичный сценарий: внутри статического метода Main разработчик пытается напрямую прочитать обычное поле класса, и сборка проекта останавливается с этим сообщением.
Ошибка относится к числу самых частых у начинающих программистов на C#, особенно у тех, кто переходит с процедурных языков или только осваивает объектно-ориентированное программирование. Хорошая новость: причина всегда одна и та же, и исправляется она за пару минут, если понимать разницу между статическими и нестатическими членами класса.
Что означает ошибка CS0120
Каждый класс в C# — это шаблон, а объекты (экземпляры) создаются по этому шаблону оператором new. Нестатическое поле существует только внутри конкретного экземпляра: у двух объектов одного класса значения этого поля могут отличаться. Поэтому компилятор требует указать, чьё именно поле вы хотите прочитать или изменить.
Сообщение «требуется ссылка на объект» буквально говорит: передайте экземпляр, к которому относится обращение. Без ссылки компилятор не знает, из какого объекта брать значение, и прерывает компиляцию.
CS0120 возникает, когда к нестатическому члену класса обращаются без экземпляра. Решений два: создать объект либо сделать член статическим.
Типичный пример возникновения ошибки
Рассмотрим минимальный код, который гарантированно вызывает CS0120:
class Program
{
int counter = 0;
static void Main()
{
counter = 5; // Ошибка CS0120
}
}
Здесь поле counter — нестатическое, то есть принадлежит объекту, а метод Main — статический и существует без всякого объекта. Внутри статического контекста нет скрытой ссылки this, поэтому обращение к counter невозможно.
Аналогичная ситуация возникает при обращении через имя класса: Program.counter = 5;. Это тоже ошибка — имя класса не является ссылкой на объект.
Способ 1: создать экземпляр класса
Самый правильный вариант в большинстве случаев — создать объект и работать через него. Так вы сохраняете объектно-ориентированную структуру программы.
static void Main()
{
Program program = new Program();
program.counter = 5; // Ошибки нет
}
Оператор new Program() выделяет память под объект, а переменная program становится той самой ссылкой, которой не хватало компилятору. Теперь все нестатические поля, свойства и методы доступны через точку после имени переменной.
☑️ Проверка перед исправлением CS0120
⚠️ Внимание: не создавайте новый экземпляр в каждой строке обращения без необходимости. Каждый вызов new порождает отдельный объект со своими значениями полей — изменения в одном экземпляре не отразятся в другом.
Способ 2: сделать член статическим
Если поле или метод по смыслу общие для всего класса и не зависят от состояния конкретного объекта, допустимо добавить модификатор static:
class Program
{
static int counter = 0;
static void Main()
{
counter = 5; // Работает
}
}
Статическое поле существует в единственном экземпляре на весь класс и доступно без создания объекта. Это уместно для счётчиков, настроек, кэшей и вспомогательных функций-утилит.
Однако увлекаться static не стоит. Злоупотребление статическими членами делает код жёстко связанным, затрудняет тестирование и приводит к ошибкам в многопоточных программах, где несколько потоков одновременно меняют общее состояние.
Сравнение двух подходов
| Критерий | Экземпляр (new) | Статический член |
|---|---|---|
| Состояние | Своё у каждого объекта | Общее для всего класса |
| Доступ | Через ссылку на объект | Через имя класса |
| Тестирование | Легко изолировать | Сложнее, общее состояние |
| Многопоточность | Безопаснее при разделении объектов | Требует синхронизации |
| Типичное применение | Данные и логика сущностей | Утилиты, константы, кэш |
Ошибка в статических методах и конструкторах
Отдельный частый случай — обращение к нестатическому методу из статического. Например, из Main вызывается обычный метод PrintInfo() без объекта. Компилятор выдаёт ту же CS0120, потому что нестатический метод неявно использует this.
Решение идентично: либо создайте экземпляр и вызовите метод через него, либо, если метод не использует данные объекта, объявите его статическим. Проверьте тело метода: если внутри есть обращения к нестатическим полям, делать его статическим нельзя — ошибка просто переместится внутрь метода.
В Visual Studio и Rider наведите курсор на подчёркнутое имя члена — среда покажет, статический он или нет, и предложит быстрые исправления через лампочку (Ctrl+точка).
⚠️ Внимание: добавление static к методу, который внутри обращается к нестатическим полям, не решает проблему — компилятор выдаст CS0120 уже внутри этого метода. Сначала приведите в порядок все зависимости.
Ошибка в Unity и других фреймворках
В Unity ошибка CS0120 часто возникает при обращении к компоненту другого скрипта через имя класса: PlayerScript.health = 100;. Компоненты в Unity всегда привязаны к конкретному игровому объекту, поэтому нужна ссылка на экземпляр.
Типичные способы получить такую ссылку в Unity:
- 🔧 Объявить публичное поле и перетащить объект в инспекторе
- 🔍 Использовать
FindObjectOfType<PlayerScript>()для поиска единственного экземпляра на сцене - 🔗 Получить компонент через
GetComponent<PlayerScript>()на том же объекте - 📦 Передать ссылку параметром при вызове метода
Конкретный подход зависит от архитектуры проекта: для связей внутри одного объекта достаточно GetComponent, для связей между сценариями удобнее поля в инспекторе.
Почему статические члены существуют без объекта
Статические поля и методы размещаются в памяти один раз при загрузке типа и принадлежат самому классу, а не его экземплярам. Поэтому к ним можно обращаться через имя класса в любой момент. Нестатические же члены создаются вместе с объектом оператором new и уничтожаются сборщиком мусора, когда на объект не остаётся ссылок.
Как быстро диагностировать проблему
Алгоритм поиска причины прост. Сначала посмотрите на номер строки в сообщении компилятора — среда разработки обычно подчёркивает проблемное место красной волнистой линией ещё до сборки. Затем ответьте на два вопроса: статический ли контекст, откуда происходит обращение, и статический ли член, к которому вы обращаетесь.
Если контекст статический, а член — нет, у вас ровно два пути, описанных выше. Выбор между ними определяется смыслом: данные принадлежат объекту — создавайте экземпляр, данные общие для всех — используйте static.
- ✅ Ошибка указывает на поле — проверьте его объявление на наличие
static - ✅ Ошибка внутри
Main— вспомните, чтоMainвсегда статический - ✅ Ошибка при обращении через имя класса — замените имя класса на переменную-экземпляр
- ✅ Ошибка после добавления
staticк методу — ищите нестатические обращения внутри него
Диагностика CS0120 сводится к одному вопросу: откуда и к чему идёт обращение. Статический контекст плюс нестатический член — всегда ошибка, исправляемая экземпляром или модификатором static.
Часто задаваемые вопросы
Почему ошибка возникает именно в методе Main?
Метод Main — точка входа программы и по определению статический: он вызывается до создания каких-либо объектов. Поэтому любое обращение к нестатическим членам из Main требует предварительного создания экземпляра через new.
Можно ли просто сделать все поля статическими?
Технически можно, но это плохая практика. Вы потеряете возможность иметь несколько независимых объектов, усложните тестирование и рискуете получить трудноуловимые ошибки при параллельной работе. Статическими стоит делать только действительно общие данные и методы-утилиты.
Что означает «ссылка на объект» простыми словами?
Это переменная, которая указывает на созданный в памяти экземпляр класса. Например, в строке Program p = new Program(); переменная p — и есть ссылка на объект. Именно её компилятор просит предоставить в сообщении CS0120.
Ошибка появилась в Unity при обращении к другому скрипту. Что делать?
Скорее всего, вы обращаетесь к скрипту через имя класса. Получите ссылку на конкретный экземпляр: через публичное поле в инспекторе, GetComponent или FindObjectOfType. После этого обращайтесь к полям и методам через полученную переменную.
Почему после добавления static ошибка переместилась в другое место?
Метод, который вы сделали статическим, внутри обращается к нестатическим полям или методам. Теперь компилятор указывает на них. Нужно либо сделать статическими и эти члены, либо вернуться к варианту с созданием экземпляра.