Matthew Young Matthew Young - 1 month ago 13
C# Question

Visual Studio Breakpoint Problems

I keep having all of my array populated with the same object in my game, which uses this array to keep track of the list of spawned objects. It has code that is basically:

for(int i = 0; i < wildPets.Length; i++)
{
Pet pet = new Pet();
wildPets[i] = pet;
}


now when I just run the code, all the pets are the same, as in it just did one new pet and assigned it to every index of the array (same name, id, hp, etc.). I used the breakpoint feature to check why this was happening and noticed that when I step through the code, the objects are always different, but with no breakpoint the error occurs. I thought the breakpoint was a really useful feature but now I don't know if its really representing my code accurately. Is there something I'm missing here. I have sample code that can be posted

Constructor:

public Pet()
{
Random r = new Random();

type = ToType(r.Next(10));

double temp = (GetHP(type, r));

if (temp > 0)
{
hp5 = temp;
}

temp = (GetSpeed(type, r));
if (temp > 0)
{
speed5 = temp;
}

level = r.Next(5, 16);
rarity = r.Next(100);
rarityLevel = GetRarity();
DisplayImage = frmMain.petImages[petID];
abilities = FillAbilities(type, abilities);
}


It makes a new pet with random level, rarity, ID, and other things. I'm using the watch section is visual studio. Two images show the method running in the background and what the array has in it, and when I set the breakpoint and step through it line by line. One has an array full of pets with the same ID (same everything, the ID is just a quick way to note) and the other has an array full of new different pet objects, like how the code should run.

all the same pet (no breakpoint)
enter image description here

all different pets (with breakpoint)
enter image description here

Answer

The reason for this is that you are creating a new Random object in your constructor each time it is called. The Random() constructor uses the current system time to generate a new random seed. When you step through the code in the debugger, enough time passes between each successive call that a new seed is generated for every Pet. When you run the code without debugging, however, the code executes quickly enough that the random seed does not change.

Move the creation of the Random object outside of your constructor. For example:

public class Pet
{
    private static readonly Random _rand = new Random();

    public Pet()
    {
        type = ToType(_rand.Next(10));
        // ...
    }
}

You may consider passing the random seed or random object as a parameter to the constructor (or to a static method or factory method that initializes the object). This would allow you to deterministically create Pet objects if needed.

A better approach would be to create a random number generating interface and pass that to the constructor, permitting the random number generator to be changed out later or mocked for testing purposes.