在 System.Collections 命名空間中,BitArray 類別提供了一種緊湊的布林值陣列表示方式,其底層實際上是以 int[] 陣列儲存位元資料。MSDN 文件曾以此為例展示如何實作索引器,本文將深入剖析該範例,並針對原始實作進行優化,使邏輯更直觀易懂。
public class MyBitArray
{
private int[] m_Bits;
private int m_Length;
public MyBitArray(int length)
{
// 計算所需 int 陣列長度:每個 int 可存 32 位元
m_Length = (length - 1) / 32 + 1;
m_Bits = new int[m_Length];
}
public bool this[int index]
{
get { return (m_Bits[index / 32] & 1 << index) != 0; }
set
{
if (value)
m_Bits[index / 32] |= 1 << index;
else
m_Bits[index / 32] &= ~(1 << index);
}
}
}
每個 int 佔 4 位元組(32 位元),故所需陣列長度為 (length - 1) / 32 + 1。減 1 是為了處理邊界值:當 length = 32 時,(32-1)/32+1 = 1,僅需一個 int;若直接用 length/32 則會得到 2,造成浪費。同理 length = 0 時結果也為 1,符合預期。
位元資料分段儲存於 int 元素中。index / 32 定位目標 int,1 << index 將 1 移至對應位置,再透過位元 AND/OR 操作完成讀寫。此機制類似記憶體管理中的分頁概念。
set 方法帶參數,索引器的 get 和 set 均帶預設參數 index。static,索引器則不可。C# 位移運算在位移量溢出時會自動取模。對 int、byte、short 皆以 32 為模;long 則以 64 為模。例如:
8 >> 33 等同 8 >> 1,結果為 4。1 << 32 等同 1 << 0,結果為 1。short b = 1; b <<= 16; 結果為 0(非取模 16),因 CLR 固定以 32 為模。long l = 1; l <<= 32; 結果為 4294967296(2^32),因 long 取模 64。理解 BitArray 內部結構與位移運算特性,有助於撰寫高效能的位元操作程式碼。本文優化後的索引器實作更具可讀性,適合作為教學或實務參考。