2

我在一个类中有一组类(体素)。我使用以下方法在数组中添加和删除。备忘录模式用于存储每个方法的操作,以便可以在任何时候撤消/重做。

    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 值自动更新。

4

3 回答 3

2

如何正确引用数组中的体素,以便在数组更新时 voxelSelected 值自动更新。

不要存储 a 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
于 2012-10-10T12:09:51.133 回答
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;
    }
}
于 2012-10-10T12:24:12.120 回答
0

If 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 ! */
于 2012-10-10T11:57:08.797 回答