I need to reference a variable from a non static class in a non static class constructor. [c#]
I need to reference a variable from a non static class in a non static class constructor. [c#]
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 :^/.
Welcome to SO. Please post a Minimal, Complete, and Verifiable Example 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 at 17:21
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 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 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 at 18:23
3 Answers
3
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.
this
merkur
venera
this.merkur
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.
this
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.
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.
merkur
venera
This is not allowed because there's no guarantee that merkur
will be initialzed before venera
, so the compiler doesn't like that.
merkur
venera
Assuming that merkur.x
is the same as Sun.x
, you can use that to initialize venera
as well.
merkur.x
Sun.x
venera
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.
reminder
defaultReminder
NullReferenceException
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.
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
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 at 17:20