我在课堂上有一系列课程(Voxel)。我使用以下方法添加和删除数组。 memento模式用于存储每个方法的动作,因此可以在任何时候撤消/重做。
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
}
在另一个类中,我希望引用上述类所持有的体素数组中的特定体素。
private Voxel voxelSelected = null;
作为参考类型,我希望这个值能够自动知道它“指向”数组的部分何时保持体素或为空。这在使用撤消命令时很重要,因为体素可以从数组中删除并变为空,反之亦然。
要从数组中获取体素,我使用以下方法。
public Voxel GetVoxel(int x, int y, int z)
{
return frames[currentFrame].Voxels[z * width * height + y * width + x];
}
然后我按如下方式设置对体素的引用。
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)
如何正确引用数组中的体素,以便在阵列更新时voxelSelected值自动更新。
答案 0 :(得分:2)
如何正确引用数组中的体素,以便在阵列更新时voxelSelected值自动更新。
不要存储Voxel
,而是存储获取体素所需的坐标。
而不是
Voxel voxelSelected;
public void SetVoxelSelected(ref Voxel voxel) { voxelSelected = voxel; }
有
int selectedX, selectedY, selectedZ
public void SetVoxelSelected (int x, int y, int z) { selectedX = x; ... }
public Voxel GetVoxelSelected() { return voxelMeshEditor.GetVoxel(x, y, z) }
给
SetVoxelSelected(0, 0, 0); //Set selected
Console.WriteLine(GetVoxelSelected() == null); // False, CORRECT !
voxelMeshEditor.RemoveVoxel(0, 0, 0); //REMOVE
Console.WriteLine(GetVoxelSelected() == null); // True
答案 1 :(得分:1)
您可以尝试使用以下包装器:
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;
}
}
并且传递VoxelReference的实例而不是Voxel。然后,您可以通过以下方式使用它:((Voxel)voxelReference)
或voxelReference.Target
当然,您可能希望将上述类更改为T的通用类。 或者存储坐标而不是索引。
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;
}
}
答案 2 :(得分:0)
如果<{strong> Voxel
是reference
类型,您已经有了直接引用,以您在代码中呈现的方式执行此操作提供。
请注意,使用Undo/Redo
轻松获得value types
,其中Lightweight
结构仅包含适用于Undo/Redo
的属性和分配给它们的值。
在这种情况下,具有不变性,使事情变得更容易。
但是,当然,我不知道在你的具体情况下这是否是一个方便的选择。
在你的例子中:
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 ! */