Why would this give out a NullReferenceException? - c#

I have a method caller addColisionBox and when i call it and setting values to it i get nullpointer at the place im calling it.. I will show some code:
public void addCollisionBox(int x, int y, int arrayNum)
{
//Creating a new rectangle at the x & y cord passed in
rectangle[arrayNum] = new Rectangle(x, y, R_Width, R_Height);
}
And i created inside another class like this:
CollisionHandler collision;
....
//CurrentX and CurrentY position to pass into addCollisionBox method and at the array number i
collision.addCollisionBox(currentX, currentY, i);
And it says in a message box that Visual C# express give out that: "Object reference not set to an instance of an object."

You didn't initalize your collision object. You should have something similar to the following. e.g.
CollisionHandler collision = new CollisionHandler();
...or how ever you are creating/grabbing an instance of your object prior to using it.

You have not created another instance, all you have done is create a variable of a given type.
CollisionHandler collision = new CollisionHandler();
// ^ variable ^ instance of object

You have not created an instance of your CollisionHandler object. Try something like this:
CollisionHandler collision = new CollisionHandler();
....
//CurrentX and CurrentY position to pass into addCollisionBox method and at the array number i
collision.addCollisionBox(currentX, currentY, i);

you need
CollisionHandler collision = new CollisionHandler();
You've just declared the variable but not set it to anything, hence the null reference exception.

I would suggest that collision is null when you're trying to call the addCollisionBox method on it, thereby causing the null dereference. If it definitely has a value at some stage then you're probably deleting it somewhere, but given the code you've pasted it seems more likely that you just need to create an instance of CollisionHandler as it doesn't appear that you're doing so.
CollisionHandler collision = new CollisionHandler();

Related

C#: default value for Vector in constructor

I have the following problem:
I have a classs that takes a position as a Vector2 in its constructor. Now, in some cases I don't know the position and want to change it at another place in the code. Since you can't make a Vector2 = null in C#, is there any default value for a Vector2 to signalize: "This Vector has no Value"?
This is the constructor in question:
public SoundEvent(SoundEffects sound, Vector2 soundOrigin)
I want to be able to call this constructor either with the SoundEffect only, or with the SoundEffect and position.
This is a better way:
public SoundEvent(SoundEffects sound, Vector2? soundOrigin = null)
Vector2 so;
if (soundOrigin == null)
so = new Vector2(); // default to origin?
else
so = soundOrigin;
The extra variable so guarantees null uses will not throw errors later.
Nullable<Vector2> is what I was looking for.

Unnecessary assignment of a value to 'player"

I am having a problem assigning values in my function. Here is my code
//Player cents
private int add_cents = 3;
public int player_1, enemy_1, enemy_2, enemy_3;
public void players_ready()
{
add_cents_player(player_1, add_cents);
}
public void add_cents_player(int player, int cent_v)
{
player = player + cent_v;
}
I want to be able to call this function and input whoever is the active player (player) and increase their value by (cent_v). However, player = player + cent_v; is saying "Unnecessary assignment of a value to 'player" and I don't understand why. It wouldn't be possible to hard code, as it is dependant on what who is the active player.
One option is to change the method return type:
private int add_cents = 3;
public int player_1, enemy_1, enemy_2, enemy_3;
public void players_ready()
{
player_1 = add_cents_player(player_1, add_cents);
}
public int add_cents_player(int player, int cent_v)
{
return player + cent_v;
}
int is a value type. It is passed by value meaning the player will actually be a copy of player_1. If you then change the player inside your method this doesn't affect in any way the player_1 since it is no reference and no relationship between them.
It looks like what you wanted to do would be using ref in order to "force" the value to be passed by reference
public void players_ready()
{
add_cents_player(ref player_1, add_cents);
}
public void add_cents_player(ref int player, int cent_v)
{
player += cent_v;
}
thus that after calling players_ready the value player_1 is actually increased
There are 2 ways to pass a variable to a function. 1 is by reference, meaning you pass a reference to a variable into the function. This is what happens with variables of type object - not the whole object's memory is copied and supplied to the function, but only an address to the piece of memory where that object resides.
For int, float etc. this is different. The values are passed by value.
Also see the relevant msdn docs.
There is a fundamental difference between the two options: reference types are passed by reference and can be altered and the original object also gets altered. E.g. this works:
class MySimpleObject // an object is a reference type
{
public int someValueType; // int is a value type
}
...
var x = new MySimpleObject();
myFunc(x); // increment x.someValueType by 5
This does not count for objects passed by value, which is what happens with int, as its a value type. Therefore your function does nothing, because its only manpulating the local value, the reference is not passed.
var player_1 = 5;
add_cents_player(player_1, 15);
// Player_1 is still 5
add_cents_player(player_1, 15);
// Player_1 is still 5
...
And thats what the compiler is complaining about; you're adding a value to the local parameter in the function. But since you don't return this, or read the value at some point the compiler is like 'hey this code does nothing, and therefore its better to remove it.

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 :^/.
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.
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.
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.

Structs: field must be fully assigned compiler error

I've declared the following struct:
struct StartPositions
{
public Vector2 pacman;
public Vector2[] ghosts;
// Constructor accepts a Vector2, and an array of Vector2's.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
for(int a=0;a<ghostsPosIn.Length;a++)
{
ghosts[a] = ghostsPosIn[a];
}
}
}
However I get a compiler error saying the ghosts field must be fully assigned. What I want to do is pass in a Vector2, and a Vector2 array when I create a StartPositions object - making a copy of that array.
How can I do this correctly?
You did not initialize the ghosts array. You need to add a call to new.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
ghosts = new Vector2[ghostsPosIn.Length];
....
}
And you can simplify the code by replacing the for loop with a call to Array.Copy().
Array.Copy(ghostsPosIn, ghosts, ghosts.Length);
You have to initialize your ghosts array first:
struct StartPositions
{
public Vector2 pacman;
public Vector2[] ghosts;
// Constructor accepts a Vector2, and an array of Vector2's.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
pacman = pacmanPosIn;
ghosts = new Vector2[ghostsPosIn.Length];
for(int a=0;a<ghostsPosIn.Length;a++)
{
ghosts[a] = ghostsPosIn[a];
}
}
}
You didn't initialize ghosts array.
public StartPositions(Vector2 pacmanPosIn, Vector2[] ghostsPosIn)
{
...
ghosts = new Vector2[ghostsPosIn.Length];
...
}
From C# Language Specification;
Actual array instances are created dynamically at run-time using the
new operator. The new operation specifies the length of the new array
instance, which is then fixed for the lifetime of the instance.
One annoying quirk in .net is that unless one is using "unsafe" code the concept of a value-type array does not exist. The struct as shown contains a position for the "pacman" and a reference to a mutable array that holds the positions of the ghosts. This is an evil combination, since the struct may appear to encapsulate the positions of the ghosts, but it does not. Thus, if one were to say:
StartPositions p1 = whatever();
... do some stuff
StartPositions p2 = p1;
p2.pacman.X += 3;
p2.ghosts[0].X += 3;
the code would add three to p2.pacman and p2.ghosts[0]; it would not affect p1.pacman.X but would add three to p1.ghosts[0]. Such behavior would likely cause confusion.
If your intention is that StartPositions will be read-only, it should probably never expose the ghosts array directly; instead, ghosts should be a property of type IList<Vector2>, and your constructor should set it to something like a new ReadOnlyList<Vector2> initialized with a copy of the passed-in positions. If it does that, then ghosts can simply be a read-only property that returns such positions.

XNA's Vector2 class, property returns an error when attempting to change its value

I will first illustrate my issue with some code:
class ExampleClass
{
private Vector2 _myVector;
public Vector2 MyVectorProperty { get { return _myVector; } set { _myVector = value; } }
private void MyMethod()
{
_myVector = Vector2.Zero; // Setting to zero
MyVectorProperty.X = 5; //Cannot modify the expression because it is not a variable (returns an error)
_myVector.X = 5; //Works fine!
}
}
As you can see, I am getting the error "Cannot modify the expression because it is not a variable" when trying to change the value of X and Y on the vector using the property. I am unsure why this happens and haven't had any luck looking on the net and i was wondering why this is and how (if) I can fix it?
Another sub question, is it good programming practice to use the public properties or the private/protected fields when working inside the class they belong to?
You should be happy compiler does not let you do so, otherwise you'll be really surprised with result of operation being lost.
MyVectorProperty is property - which means getting the value is call to a function returning the value (something like this.get_MyVectorProperty()).
Since type of the MyVectorProperty is Vector2 which is struct it means that value returned by the get_... function is a copy of value, not reference like it would be in case of normal class.
Changing field X of above copy would simply change X inside of copy of the value, and since that copy of the value is not assigned to anything it will be lost.
Vector2 is a struct (value type), so your property returns the value of _myVector (i.e. a copy) and you can't change that.

Categories

Resources