NeoKuro
NeoKuro

Reputation: 457

Struct variables not changing

I feel like I'm missing something complete obvious so I apologise in advance if (when?) that is the case. I'm trying to do something really simple, change a bool value in a struct from false to true. Obviously I can't change it directly, so I created a method within the struct that I can call which should change the value there. It doesn't seem to be the case. Here is the code and I'd appreciate any insight;

public Dictionary<int, List<ScanLineNode>> allScanLineNodes = new Dictionary<int, List<ScanLineNode>>();

public void MethodName(ScanLineNode node [...])
{       
    //This will perform a raycast from the Node's position in the specified direction. If the raycast hits nothing, it will return Vector3.zero ('Row is complete'), otherwise will return the hit point

    Vector3 terminationPoint = node.RaycastDirection(node, direction, maxDist, targetRaycast, replacementColour, backgroundColour);

    ScanLineNode terminationNode = new ScanLineNode();

    //Previously attempted to store a local reference to this row being used, but also did not work
    //List<ScanLineNode> rowNodes = allScanLineNodes[node.rowNumber];

    [...]

    if (terminationPoint == Vector3.zero)
    {
        //Definitely reaches this point, and executes this function along the row, I have added breakpoints and checked what happens in this for loop. After running 'RowComplete' (which just changes 'rowComplete' from false to true) 'rowComplete' is still false. Just in case I've included the RowComplete() function below.

        Debug.Log("Row Complete: " + node.rowNumber);
        for (int i = 0; i < allScanLineNodes[node.rowNumber].Count; i++)
        {
            allScanLineNodes[node.rowNumber][i].RowCompleted();
        }
    }
}

ScanLineNode Struct -- Most stuff is hidden (that I don't believe is affecting this), I have included the RowComplete() function however.

public struct ScanLineNode
    {
        [...]
        public bool rowComplete;
        [...]

        public ScanLineNode([...])
        {
            [...]
            rowComplete = false;
            [...]
        }

        public void RowCompleted()
        {
            rowComplete = true;
        }
    }

I have also confirmed that RowCOmpleted() does not get called anywhere aside the above location, and 'rowComplete' is only called from the RowComplete() function

Upvotes: 1

Views: 1368

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1064104

(from comments) allScanLineNodes is a Dictionary<int, List<ScanLineNode>>

Right; the indexer for a List<ScanLineNode> returns a copy of the struct. So when you call the method - you are calling it on a disconnected value on the stack that evaporates a moment later (is overwritten on the stack - this isn't the garbage collector).

This is a common error with mutable structs. Your best bet is probably: don't make mutable structs. But... you could copy it out, mutate it, and then push the mutated value back in:

var list = allScanLineNodes[node.rowNumber];
var val = list[i];
val.RowCompleted();
list[i] = val; // push value back in

But immutable is usually more reliable.

Note: you can get away with this with arrays, since the indexer from an array provides access to a reference to the in-place struct - rather than a copy of the value. But: this isn't a recommendation, as relying on this subtle difference can cause confusion and bugs.

Upvotes: 7

Related Questions