[英]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文檔中對此進行了解釋:
結構在分配時被復制。 將結構分配給新變量后,將復制所有數據,並且對新副本的任何修改都不會更改原始副本的數據。 使用諸如字典之類的值類型集合時,記住這一點很重要。
對於將s分配給變量時如何處理struct
,您似乎存在誤解。 struct
是值類型,因此當您為var something = struct
賦值時,變量不會收到對struct
對象的引用,這與類(引用類型)不同; 而是接收該struct
表示的value
的副本。
考慮到這一點,像var face = m_mesh.Faces[f];
這樣的賦值 不會像您期望的那樣工作。 你處理face
的第一個for-loop
,不會影響原有的m_mesh.Faces[f]
除非你重新分配face
回m_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.