Я пытаюсь создать солнечную систему с естественными спутниками. В настоящее время я рисую планеты относительно статического объекта класса «Солнце», но я бы хотел, чтобы класс использовал положение другого объекта планеты и рисовал относительно этой планеты. Для этого мне нужно извлечь координаты 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 постоянно обновляется с каждым тиком, поэтому мне нужно постоянно обновлять его: ^ /.
Добро пожаловать в SO. Отправьте Минимальный, полный и проверяемый пример, чтобы воспроизвести вашу проблему. Кроме того, вместо ссылки на снимки экрана скопируйте сюда соответствующие фрагменты кода.
Лучше вырезать и вставить код (и любые сообщения об ошибках) в ответ и использовать инструмент форматирования кода.
Вы можете рассмотреть два метода: (1) сделать ваши структуры данных неизменный. То есть снимок солнечной системы в определенное время. Когда вы делаете шаг по времени, вы создаете снимок новый. Это действительно не потребляет столько памяти; орбитальные характеристики планет в определенное время можно суммировать, вероятно, в пару десятков двойников с хорошим приближением. А это означает, что вы можете легко сохранять снимки, запускать симуляцию вперед и назад и так далее. Также легче рассуждать о непротиворечивых данных, потому что они не меняются.
И (2) рисунок относительно точки, отличной от начала координат, - это линейное преобразование. Прочтите, как можно представить относительные положения, масштабы и повороты с помощью матриц. (en.wikipedia.org/wiki/Linear_map) Часто вы можете изменить свою систему координат "просмотра", просто применив матричное умножение к каждой точке в системе, что довольно просто сделать.





Первое попадание в простой поиск в 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
reminderwill be initialized beforedefaultReminder, so the above line might throw aNullReferenceExceptionat 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.
Основная рекомендация - старайтесь как можно больше не использовать статику. Вместо этого прочтите о Инверсия контроля и Внедрение зависимости и о том, что такое локатор сервисов в целом. Ваша проблема на самом деле довольно распространенная, и концепция IoC очень помогает вам разрабатывать ваши приложения на уровне профессиональных разработчиков.