2012-10-10 36 views
2

我在一個類中有一個類的數組(Voxel)。我使用以下方法添加到數組中並從中移除。備忘錄模式用於存儲每種方法的操作,以便可以隨時撤消/重做。如何在包含數組的類的外部引用數組元素?

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 
    } 

在一個單獨的I類希望有通過上述類保持體素的陣列中的特定體素的參考。

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

你在混淆。你的體素變量指向一個體素對象而不是數組槽。清除數組插槽對它指向的體素對象沒有任何作用。對於你所描述的你需要一個指向陣列插槽的對象(這是btw而不是Voxel)。你需要一個不同的設計來做到這一點 – Eddy

回答

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 
0

如果Voxelreference類型,你已經有了一個直接參考它,在你出現在代碼中提供的方式做這件事。

應該注意,Undo/Redo容易與value types achived,一些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 ! */ 
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; 
    } 
} 
相關問題