Conor Watson Conor Watson - 2 months ago 6
C# Question

Copy Constructor in C# still holds its references

I am currently writing a Level Generation program in Windows Forms and C#. Each level is created from a series of 'patterns' which are loaded into an array at startup. When creating a level the program will randomly select a number of patterns from this array, randomly rotate them and create the level. Each pattern that is selected is stored in a

chosenPattern
variable so that it can be rotated without modifying the original pattern.

Here is the code I use to choose the pattern and rotate it.

int rand = randomNumber(0, patterns.Count - 1);
Level chosenPattern = new Level(patterns[rand]);
chosenPattern = rotatePattern(chosenPattern, randomNumber(0, 3));


And here are the Level constructors, including the Copy Constructor.

public class Level
{
public List<List<char>> grid;
public string solution;
public int difficulty;
public TimeSpan generationTime;

public Level()
{
grid = new List<List<char>>();
solution = "";
difficulty = 0;
generationTime = TimeSpan.MinValue;
}

public Level(Level level)
{
grid = level.grid;
solution = level.solution;
difficulty = level.difficulty;
generationTime = level.generationTime;
}
}


However even when using the Copy Constructor, the pattern stored in the array is still rotated when rotating the stored pattern, and I am unsure why (Note: I'm a fairly novice C# programmer)

and the RotatePattern function:

public Level rotatePattern(Level pattern, int rotation)
{
Level tempPattern = pattern;

switch (rotation)
{
case 1:
//Rotate 90 - Reverse Each Row
for(int i = 0; i < tempPattern.grid.Count; i++)
{
tempPattern.grid[i].Reverse();
}
break;

case 2:
//Rotate 180 - Reverse Each Row, then Each Column
for (int i = 0; i < tempPattern.grid.Count; i++)
{
tempPattern.grid[i].Reverse();
}

tempPattern.grid.Reverse();
break;

case 3:
//Rotate 270 - Reverse Each Column
tempPattern.grid.Reverse();
break;
}

return tempPattern;
}

Answer

In your copy constructor, replace it with

public Level(Level level)
{
     grid = level.grid.Select(x=>x.ToList()).ToList();
     solution = level.solution;
     difficulty = level.difficulty;
     generationTime = level.generationTime;
}

Simply passing List will copy the reference instead of the value