-2

I'm trying to make a solar system with natural satellites. Currently I'm drawing a planets relative to a static "Sun" class object, but i wold like to make the class use a position of another planet object and draw relative to that planet. To do that i need to extract the x and y position of that planet object.

This is the class constructor of a class i use for drawing planets.

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);

This is the class constructor.

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;
}

The x and y position constantly update with every tick so i need it constantly update it :^/.

Hazel へいぜる
  • 2,751
  • 1
  • 12
  • 44
Major Tom
  • 1
  • 1
  • Main recomendation - try not to use static as much as possible. Instead, read about *Inversion of Control* and *Dependency Injection* and what is service locator in general. Your problem is actually a pretty common one and IoC concept greatly help you to develop your applications on the level of professional developers. – eocron Jun 29 '18 at 17:20
  • Welcome to SO. Please post a [Minimal, Complete, and Verifiable Example](https://stackoverflow.com/help/mcve) so your problem can be reproduced. Also, instead of linking to screenshots, please copy-paste the relevant bits of your code here. – Sach Jun 29 '18 at 17:21
  • 2
    **Please never post screenshots of code to SO** unless your question is actually about some element of the debugger UI. It's hard to read, we can't cut-n-paste it, and so on. – Eric Lippert Jun 29 '18 at 17:35
  • Rather, cut-n-paste the code (and any error messages) into the answer, and use the code formatting tool. – Eric Lippert Jun 29 '18 at 17:42
  • Two techniques you might consider using are (1) to make your data structures *immutable*. That is, a snapshot of the solar system at a particular time. When you time-step, you create a *new* snapshot. This really doesn't consume that much memory; the orbital characteristics of the planets at a particular time can be summed up in probably a couple dozen doubles to a good approximation. And it means that you can easily store snapshots, run your simulation forwards and backwards, and so on. It's also easier to reason about data that is consistent because it does not change. – Eric Lippert Jun 29 '18 at 18:23
  • And (2) drawing relative to a point other than the origin is a *linear transformation*. Consider reading up on how you can represent relative positions, scales and rotations using matrices. (https://en.wikipedia.org/wiki/Linear_map) Often you can change your "view" coordinate system by simply applying a matrix multiplication to every point in the system, which is pretty straightforward to do. – Eric Lippert Jun 29 '18 at 18:25

3 Answers3

5

It is illegal to use this in any way in a field initializer. merkur in your initializer of venera is actually this.merkur, so it counts.

C# prevents this because that technique is a common source of bugs. Field initializers run before the constructor bodies, including the constructor bodies of base class constructors. If C# did not restrict you from accessing this it would be extremely easy to access a property or call a method that was not yet ready to be used.

See https://blogs.msdn.microsoft.com/ericlippert/2008/02/15/why-do-initializers-run-in-the-opposite-order-as-constructors-part-one/ for more details on the order in which constructor initializers run.

What you should do is move all your field initializers into the constructor body. Then you are responsible for ensuring that the statements in the body run in the correct order to do the initialization you want.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
0

The first hit in a simple Google search should solve this problem.

Essentially, your problem is you're using one instance variable (merkur) to initialize another instance variable (venera) in your code.

This is not allowed because there's no guarantee that merkur will be initialzed before venera, so the compiler doesn't like that.

Assuming that merkur.x is the same as Sun.x, you can use that to initialize venera as well.

Sach
  • 10,091
  • 8
  • 47
  • 84
0

The compiler won't allow you to initialize one instance field with properties from another. Instead I would recommend initializing your fields within whatever method is executed first (such as the Form.Load event). This will allow you to properly initialize your fields prior to processing any information with them. For example:

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);
}

Definitely feel free to reference the articles the other answers have provided, this post should also shed some light on the topic as the accepted answer there provides some good details as to why this issue is an actual issue. To quote in case the link ever dies:

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.

Also feel free to look into the Compiler Error CS0236 reference from Microsoft. It should shed some further light on the topic.

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.

Hazel へいぜる
  • 2,751
  • 1
  • 12
  • 44