C# 中結構體 (struct) 與類別 (class) 皆可作為巢狀資料容器,但兩者在記憶體模型、預設建構函式、陣列初始化行為上有關鍵差異。本文透過實際程式碼對比,釐清 結構體需手動初始化陣列元素、類別可在建構函式自動完成 等核心觀念。
定義一張「報銷單」主檔 CWSData,包含標題、企業代碼與明細陣列 CWSDataTM[];明細項目含順序號、報銷號、單據張數。
public struct CWSData
{
public string strTitle; // 標題
public string strQYCode; // 企業代碼
public CWSDataTM[] cDetailItems; // 明細陣列
}
public struct CWSDataTM
{
public string strSXH; // 順序號
public string strBXH; // 報銷號
public string strDJS; // 單據張數
}
int M = 3;
CWSData cwData = new CWSData(); // 結構體預設建構函式:所有欄位歸零/null
cwData.cDetailItems = new CWSDataTM[M]; // 僅配置陣列參考,元素仍為預設值 (null/0/false)
// 逐一指派值
cwData.cDetailItems[0].strSXH = "1";
cwData.cDetailItems[0].strBXH = "BX001";
cwData.cDetailItems[0].strDJS = "5";
// ... 其餘元素同理
struct 定義 public CWSData(),故無法在定義處自動 new 陣列元素。new CWSDataTM[M] 產生的是 M 個已初始化為零的 CWSDataTM 實例,而非 null 參考。但若巢狀層級含 string 等參考型別,該欄位仍為 null。public class CWSData
{
public string strTitle;
public string strQYCode;
public CWSDataTM[] cDetailItems;
public CWSData(int m) // 自訂建構函式
{
if (m > 0)
{
cDetailItems = new CWSDataTM[m];
for (int i = 0; i < m; i++)
cDetailItems[i] = new CWSDataTM(); // 明確實例化每個元素
}
}
}
public class CWSDataTM
{
public string strSXH;
public string strBXH;
public string strDJS;
public CWSDataTM() { } // 可定義無參數建構函式
}
int M = 5;
CWSData cwData = new CWSData(M); // 一次完成陣列配置與元素實例化
for (int i = 0; i < M; i++)
{
cwData.cDetailItems[i].strSXH = "aaa";
// ...
}
new CWSDataTM() 產生獨立堆積物件,大量資料時需考慮效能。| 特性 | 結構體 | 類別 |
|---|---|---|
| 記憶體配置 | 堆疊 / 內含於父物件 | 堆積 |
| 指派語意 | 值複製 | 參考複製 |
| 無參數建構函式 | 隱含、不可覆寫 | 可自訂 |
| 陣列元素初始化 | 自動零初始化 | 需手動 new 每個元素 |
| 適用場景 | 小型、不可變、高效能資料結構 | 複雜物件、需繼承、參考語意 |
readonly、透過建構函式 (C# 10+ 允許 struct 定義有參數建構函式) 初始化,避免防禦性複製。List<CWSDataTM> 取代陣列,彈性擴充並避免預先決定大小。string),XML/JSON 序列化行為與類別一致;二進位序列化需注意記憶體佈局。using System;
namespace NestedDemo
{
// 結構體版
public struct StructMain { public string Title; public StructSub[] Items; }
public struct StructSub { public string Code; public int Qty; }
// 類別版
public class ClassMain
{
public string Title;
public ClassSub[] Items;
public ClassMain(int count)
{
Items = new ClassSub[count];
for (int i = 0; i < count; i++) Items[i] = new ClassSub();
}
}
public class ClassSub { public string Code; public int Qty; }
class Program
{
static void Main()
{
// 結構體
var s = new StructMain { Title = "Struct", Items = new StructSub[2] };
s.Items[0].Code = "A001"; // 直接指派,Items[0] 已零初始化
// 類別
var c = new ClassMain(2) { Title = "Class" };
c.Items[0].Code = "B001"; // 建構函式已 new ClassSub()
Console.WriteLine($"{s.Title}: {s.Items[0].Code}");
Console.WriteLine($"{c.Title}: {c.Items[0].Code}");
}
}
}