Conor Watson
Conor Watson

Reputation: 617

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

Upvotes: 2

Views: 103

Answers (2)

Orel Eraki
Orel Eraki

Reputation: 12196

This is because grid property, unlike the rest of the properties, is not ValueType, thus the address is copied and not the actual values.

Copy Constructor is just a constructor that accepts the same type instance. If you assign to one of its property i.e grid, then if this property is not ValueType, then you should make a method to copy those values, plain assignment with grid = level.grid just won't cut it, and will produce the same results.

Try changing the grid assignment to the following:

grid = level.grid.Select(lst => lst.ToList()).ToList();

Upvotes: 1

Martheen
Martheen

Reputation: 5580

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

Upvotes: 3

Related Questions