簡體   English   中英

自定義結構數組不保留其值,為什么?

[英]Array of custom structs doesn't keep its values, why?

我是C#的新手,我創建了一個結構( MyMeshFace )並初始化了一個包含約40.000個結構的數組,如下所示:

MyMeshFace[] m_meshFaces = new MyMeshFace[mesh.Faces.Count]; // ~40.000 faces

然后,我將數據填充到for循環中,並使用斷點對其進行調試,以便我可以親眼看到以空值(即edge = new Line();等)實例化了字段對象,並且在初始化之后,還可以看到已將值正確分配給字段和對象字段(例如Line.From = Point;Line.To = AnotherPoint;等)。

問題 :但是,當我第二次遍歷此m_meshFaces列表時,這一次調用嵌入在struct中的函數以使struct更新其內部數據,則對象( Lines )不再具有任何值! 結構中的Line對象實際上是實例化的,因此它們是有效的對象,因此它們在訪問時不會引發異常,但是它們的值(X,Y,X)被清零(盡管我可以通過斷點看到Lines最初在初始化時在第一個循環中分配了值)。 而且我不知道為什么會這樣。

代碼很簡單:

public struct MyMeshFace
{
    public Line edgeAB;
    public Line edgeBC;
    ...
    public int facesABC[];
    public Point3d[] pointsABC;
    ...
    public void Init(Mesh m, int index)
    {
        edgeAB = new Line();
        edgeBC = new Line();
        ...
    }
    public void SetFaceData(Mesh m)
    {
        // UPDATE 3: Face corner indexes (to points) from mesh:
        var face = m.Faces[faceIndex];
        facesABC[xA] = face.A;
        facesABC[xB] = face.B;

        pointsABC[xA] = m.Vertices[facesABC[0]];
        pointsABC[xB] = m.Vertices[facesABC[1]];
        ...
        edgeAB.From = pointsABC[xA];
        edgeAB.To = pointsABC[xB];
        ...
    }
    public bool DoSomething()
    {
        if (edgeAB.From.X == 0 && edgeAB.From.Y == 0 && edgeAB.From.Z == 0)
           return false;   /* Fail ! */
        // 
        // Execution never makes it here :(
        // 
        return true;
    }
        ...
}

主要方法( 更新2 :添加了對Init和SetFaceData的調用)

public void Main()
{   
    MyMeshFace[] m_meshFaces = new MyMeshFace[m_mesh.Faces.Count];
    for (var f = 0; f < m_meshFaces.GetLength(0); f++)
    {
        var face = m_meshFaces[f];
        face.Init(m_mesh, f);
        face.SetFaceData(m_mesh);
    }

    for (var x = 0; x < m_meshFaces.GetLength(0); x++)
    {
        var face = m_meshFaces[x];
        if (face.DoSomething())
            Print("Did something!");  # <-- This never happens
    }
}

我嘗試在Microsoft的頁面上閱讀有關結構的文章,但那里沒有任何線索。 我究竟做錯了什么?


編輯FIX :根據以下答案,此代碼有效:

public void Main()
{   
    MyMeshFace[] m_meshFaces = new MyMeshFace[m_mesh.Faces.Count];
    for (var f = 0; f < m_meshFaces.GetLength(0); f++)
    {
        // var face = m_meshFaces[f];       // <-- No no!
        // face.Init(m_mesh, f);            // <-- No no!
        // face.SetFaceData(m_mesh);        // <-- No no!

        m_meshFaces[f].Init(m_mesh, f);     // <-- OK! 
        m_meshFaces[f].SetFaceData(m_mesh); // <-- OK
    }

    for (var x = 0; x < m_meshFaces.GetLength(0); x++)
    {
        if (m_meshFaces[x].DoSomething())
            Print("Did something!");  // OK!
    }
}

//羅爾夫

當您做var face = m_meshFaces[f]; 在您的代碼中(向高亮添加了注釋):

public void Main()
{   
    MyMeshFace[] m_meshFaces = new MyMeshFace[m_mesh.Faces.Count];
    for (var f = 0; f < m_faceInfo.GetLength(0); f++)
    {
        var face = m_meshFaces[f]; // <---
        face.Init(m_mesh, f);
        face.SetFaceData(m_mesh);
    }

    for (var x = 0; x < m_meshFaces.GetLength(0); x++)
    {
        var face = m_meshFaces[x]; // <---
        if (face.DoSomething())
            Print("Did something!");  # <-- This never happens
    }
}

您將獲得該結構的COPY

然后,您修改副本,並且永遠不要用副本替換原件。

在第二個循環中,對結構進行A NEW COPY


根據解決方案,您可以通過執行m_meshFaces[f] = face;將其替換為副本m_meshFaces[f] = face; 或者您可以嘗試直接使用數組中的結構:

m_meshFaces[f].Init(m_mesh, f);
m_meshFaces[f].SetFaceData(m_mesh);

在Microsoft文檔中對此進行了解釋:

結構在分配時被復制。 將結構分配給新變量后,將復制所有數據,並且對新副本的任何修改都不會更改原始副本的數據。 使用諸如字典之類的值類型集合時,記住這一點很重要。

- 結構(C#編程指南)

對於將s分配給變量時如何處理struct ,您似乎存在誤解。 struct是值類型,因此當您為var something = struct賦值時,變量不會收到對struct對象的引用,這與類(引用類型)不同; 而是接收該struct表示的value的副本。

考慮到這一點,像var face = m_mesh.Faces[f];這樣的賦值 不會像您期望的那樣工作。 你處理face的第一個for-loop ,不會影響原有的m_mesh.Faces[f]除非你重新分配facem_mesh.Faces[f]它的修改之后。


嘗試以下代碼:

public void Main()
{   
    MyMeshFace[] m_meshFaces = new MyMeshFace[m_mesh.Faces.Count];
    for (var f = 0; f < m_faceInfo.GetLength(0); f++)
    {
        var face = m_mesh.Faces[f];
        face.Init(m_mesh, f);
        face.SetFaceData(m_mesh);
        m_mesh.Faces[f] = face; //<<<-----
    }

    for (var x = 0; x < m_meshFaces.GetLength(0); x++)
    {
        var face = m_meshFaces[x];
        if (face.DoSomething())
            Print("Did something!");
        m_meshFaces[x] = face; //<<<-----
    }
}

更新:對OP中的錯字的更正使本節過時。 它將保留僅供將來參考。

另外:您似乎對數組初始化和/或結構的默認值也有誤解。

值類型,包括 struct s, 不能為null 它們總是被初始化為默認值。 由於您沒有使用任何自定義數據填充m_meshFaces數組,因此您的命令MyMeshFace[] m_meshFaces = new MyMeshFace[m_mesh.Faces.Count]; 使數組僅在默認情況下填充MyMeshFace結構。 這是因為數組初始化new array[amount]只保留了一定量(內存插槽amount對象)。 它不是在復制原始的m_mesh.Faces集合; 它將完全使用default內部值創建新的Face對象。

重要的是,如果Line也是一個結構(也初始化為默認值,可能是0 ),則...

 if (edgeAB.From.X == 0 && edgeAB.From.Y == 0 && edgeAB.From.Z == 0) return false; /* Fail ! */ 

...將永遠失敗; 因為From值始終都是default ,所以X & Y & Z可能都是0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM