Reputation: 796
I have an array of classes (Voxel) in a class. I use the following methods to add to and remove from the array. A memento pattern is used to store the action for each method so it can be undone/redone at any point.
public void AddVoxel(int x, int y, int z)
{
int index = z * width * height + y * width + x;
frames[currentFrame].Voxels[index] = new Voxel();
// Undo/Redo history
undoRedoHistories[currentFrame].Do(new AddMemento(index));
}
public void RemoveVoxel(int x, int y, int z)
{
int index = z * width * height + y * width + x;
// Undo/Redo history
undoRedoHistories[currentFrame].Do(new RemoveMemento(index, frames[currentFrame].Voxels[index]));
frames[currentFrame].Voxels[index] = null; // Does not update 'voxelSelected' reference
}
In a separate class I wish to have a reference to a particular voxel in the array of voxels held by the above class.
private Voxel voxelSelected = null;
As a reference type I would like this value to automatically know when the part of the array it "points" to holds a voxel or is null. This is important when using an undo command because a voxel can be removed from the array and become null, or vice versa.
To get a voxel from the array I use the following method.
public Voxel GetVoxel(int x, int y, int z)
{
return frames[currentFrame].Voxels[z * width * height + y * width + x];
}
I then set the reference to the voxel as follows.
public void SetVoxelSelected(ref Voxel voxel)
{
voxelSelected = voxel;
}
voxelMeshEditor.AddVoxel(0, 0, 0);
var voxel = voxelMeshEditor.GetVoxel(0, 0, 0); // Copies rather than references?
SetVoxelSelected(ref voxel);
Console.WriteLine(voxelSelected == null); // False
voxelMeshEditor.RemoveVoxel(0, 0, 0);
Console.WriteLine(voxelSelected == null); // False (Incorrect intended behaviour)
How can I correctly reference a voxel in the array so the voxelSelected value automatically updates when the array updates.
Upvotes: 2
Views: 1577
Reputation: 4927
You can try to use the following wrapper:
public class VoxelReference
{
private readonly Voxel[] m_array;
private readonly int m_index;
public Voxel Target
{
get { return m_array[m_index]; }
}
public VoxelReference(Voxel[] array, int index)
{
m_array = array;
m_index = index;
}
public static explicit operator Voxel(VoxelReference reference)
{
return reference.Target;
}
}
And pass an instance of VoxelReference everywhere instead of Voxel. Then you can use it in the following ways: ((Voxel)voxelReference)
or voxelReference.Target
Of course, you might want to change the above class to be generic of T. Or to store the coordinates instead of index.
public class ArrayElementReference<T>
{
private readonly T[] m_array;
private readonly int m_index;
public T Target
{
get { return m_array[m_index]; }
}
public ArrayElementReference(T[] array, int index)
{
m_array = array;
m_index = index;
}
public static explicit operator T(ArrayElementReference<T> reference)
{
return reference.Target;
}
}
Upvotes: 1
Reputation: 50214
How can I correctly reference a voxel in the array so the voxelSelected value automatically updates when the array updates.
Don't store a Voxel
, but store the coordinates you need to get the voxel.
Instead of
Voxel voxelSelected;
public void SetVoxelSelected(ref Voxel voxel) { voxelSelected = voxel; }
have
int selectedX, selectedY, selectedZ
public void SetVoxelSelected (int x, int y, int z) { selectedX = x; ... }
public Voxel GetVoxelSelected() { return voxelMeshEditor.GetVoxel(x, y, z) }
giving
SetVoxelSelected(0, 0, 0); //Set selected
Console.WriteLine(GetVoxelSelected() == null); // False, CORRECT !
voxelMeshEditor.RemoveVoxel(0, 0, 0); //REMOVE
Console.WriteLine(GetVoxelSelected() == null); // True
Upvotes: 2
Reputation: 62265
If Voxel
is a reference
type, you already have a direct reference to it, doing it in a way you present in code provided.
Should note, that Undo/Redo
easily achived with value types
, with some Lightweight
structure that holds only properties suitable for Undo/Redo
and values assigned to them.
Having immutability, in this case, make things a lot easier.
But, naturally, I don't know if this would be a convinient choice in your specific case.
In your example:
var voxel = voxelMeshEditor.GetVoxel(0, 0, 0); // Copy REFERENCE, and NOT value
SetVoxelSelected(ref voxel); //Set selctede vortex reference
Console.WriteLine(voxelSelected == null); // False, CORRECT !
voxelMeshEditor.RemoveVoxel(0, 0, 0); //REMOVE
Console.WriteLine(voxelSelected == null);
/* Selected vortex still pointing to the memroy location it was pointing before.
The fact is that memory location is not more in array, doesn't matter.
So CORRECT ! */
Upvotes: 0