Мне нужно ссылаться на переменную из нестатического класса в конструкторе нестатического класса. [C#]

Я пытаюсь создать солнечную систему с естественными спутниками. В настоящее время я рисую планеты относительно статического объекта класса «Солнце», но я бы хотел, чтобы класс использовал положение другого объекта планеты и рисовал относительно этой планеты. Для этого мне нужно извлечь координаты x и y этого объекта планеты.

Это конструктор класса, который я использую для рисования планет.

Nebesko_Telo merkur = new Nebesko_Telo(Sun.x, Sun.y, 4, 12, 4.090909090909091,
                                       1, 255, 255, 255);
// A field initializer cannot reference the non-static field, method,
//    or property 'Form1.merkur'.
Nebesko_Telo venera = new Nebesko_Telo(merkur.x, merkur.y, 1, 23, 1.5, 1, 176, 108, 32);

Это конструктор класса.

public Nebesko_Telo(doubl _rel_tel_x, double _rel_tel_y, double _r, double _or,
                    double _Fi_mult, double _tilt_plant_nat, int _re, int_gr, int _bl) {
    r = _r;
    or = _or;
    Fi_mult = _Fi_mult;
    re = _re;
    gr = _gr;
    bl = _bl;
    tilt_planet_nat = _tilt_planet_nat;
    rel_tel_x = _rel_tel_x;
    rel_tel_y = _rel_tel_y;
}

Положение x и y постоянно обновляется с каждым тиком, поэтому мне нужно постоянно обновлять его: ^ /.

Основная рекомендация - старайтесь как можно больше не использовать статику. Вместо этого прочтите о Инверсия контроля и Внедрение зависимости и о том, что такое локатор сервисов в целом. Ваша проблема на самом деле довольно распространенная, и концепция IoC очень помогает вам разрабатывать ваши приложения на уровне профессиональных разработчиков.

eocron 29.06.2018 19:20

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

Sach 29.06.2018 19:21
Пожалуйста, никогда не публикуйте скриншоты кода в SO, если ваш вопрос не касается какого-либо элемента пользовательского интерфейса отладчика. Его трудно читать, мы не можем вырезать-вставить-вставить и так далее.
Eric Lippert 29.06.2018 19:35

Лучше вырезать и вставить код (и любые сообщения об ошибках) в ответ и использовать инструмент форматирования кода.

Eric Lippert 29.06.2018 19:42

Вы можете рассмотреть два метода: (1) сделать ваши структуры данных неизменный. То есть снимок солнечной системы в определенное время. Когда вы делаете шаг по времени, вы создаете снимок новый. Это действительно не потребляет столько памяти; орбитальные характеристики планет в определенное время можно суммировать, вероятно, в пару десятков двойников с хорошим приближением. А это означает, что вы можете легко сохранять снимки, запускать симуляцию вперед и назад и так далее. Также легче рассуждать о непротиворечивых данных, потому что они не меняются.

Eric Lippert 29.06.2018 20:23

И (2) рисунок относительно точки, отличной от начала координат, - это линейное преобразование. Прочтите, как можно представить относительные положения, масштабы и повороты с помощью матриц. (en.wikipedia.org/wiki/Linear_map) Часто вы можете изменить свою систему координат "просмотра", просто применив матричное умножение к каждой точке в системе, что довольно просто сделать.

Eric Lippert 29.06.2018 20:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
233
3

Ответы 3

Первое попадание в простой поиск в Google должно решить эту проблему.

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

Это недопустимо, потому что нет гарантии, что merkur будет инициализирован раньше venera, поэтому компилятору это не нравится.

Предполагая, что merkur.x - это то же самое, что и Sun.x, вы также можете использовать его для инициализации venera.

Недопустимо использовать this способом любой в инициализаторе поля. merkur в вашем инициализаторе venera на самом деле является this.merkur, поэтому он считается.

C# предотвращает это, потому что этот метод является частым источником ошибок. Инициализаторы полей запускают перед тела конструктора, включая тела конструкторов конструкторов базового класса. Если бы C# не ограничивал вас в доступе к this, было бы очень легко получить доступ к свойству или вызвать метод, который еще не был готов к использованию.

См. https://blogs.msdn.microsoft.com/ericlippert/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one/ для получения дополнительных сведений о порядке, в котором запускаются инициализаторы конструктора.

Что вам нужно сделать, так это переместить все инициализаторы полей в тело конструктора. Затем вы несете ответственность за то, чтобы операторы в теле выполнялись в правильном порядке для выполнения нужной вам инициализации.

Компилятор не позволит вам инициализировать одно поле экземпляра свойствами из другого. Вместо этого я бы рекомендовал инициализировать ваши поля в любом методе, который выполняется первым (например, событие Form.Load). Это позволит вам правильно инициализировать ваши поля перед обработкой с ними какой-либо информации. Например:

Nebesko_Telo merkur = null;
Nebesko_Telo venera = null;
private void Form1_Load(object sender, EventArgs e) {
    merkur = new Nebesko_Telo(Sun.x, Sun.y, 4, 12, 4.090909090909091, 1, 255, 255, 255);
    if (merkur != null)
        venera = new Nebesko_Telo(merkur.x, merkur.y, 1, 23, 1.5, 1, 176, 108, 32);
}

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

You cannot use an instance variable to initialize another instance variable. Why? Because the compiler can rearrange these - there is no guarantee that reminder will be initialized before defaultReminder, so the above line might throw a NullReferenceException at runtime.

Также не стесняйтесь заглядывать в ссылку Ошибка компилятора CS0236 от Microsoft. Это должно пролить дополнительный свет на эту тему.

Instance fields cannot be used to initialize other instance fields outside a method. If you are trying to initialize a variable outside a method, consider performing the initialization inside the class constructor. For more information, see Methods.

Другие вопросы по теме