首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET Framework 源碼深度解析:ArrayList 與 LinkedList 實現差異與設計權衡

     編輯:關於.NET

繼上篇分析 List<T> 後,本文對比 ArrayList (非泛型) 與 LinkedList<T> (泛型) 的源碼實現,揭示兩者在 .NET 架構中的不同定位與設計取捨。

架構層級的本質區別

源碼物理路徑揭示核心差異:

  • ArrayList:redbits\ndp\clr\src\BCL\System\Collections — **CLR 基礎類庫 (BCL) 核心層**
  • LinkedList<T>:redbits\ndp\fx\src\CompMod\System\Collections\Generic — **框架擴展層 (FX/CompMod)**

結論:ArrayList 是運行時核心組件,LinkedList 是上層擴展組件。兩者層級不同,缺乏直接可比性。

ArrayList:非泛型動態陣列的經典實現


public class ArrayList : IList, ICloneable
{
    private object[] _items;
    private int _size;
    private int _version;
    [NonSerialized] private object _syncRoot;
    private const int _defaultCapacity = 4;
    private static readonly object[] emptyArray = new object[0];
    ...
}

與 List<T> 的異同

  • 相同:底層皆為 object[] 動態陣列,擴容邏輯 (2倍)、_version 迭代器失效機制、Array.Copy 批量操作幾乎一致。
  • 不同 1:型別系統 — ArrayList 存儲 object,涉及**裝箱/拆箱**開銷;List<T> 強型別,避免裝箱。
  • 不同 2:ICloneable — ArrayList 實現 ICloneable (淺複製);List<T> 未實現。淺複製語意在引用型別元素下極易誤用,設計初衷存疑。

裝箱開銷實例


public virtual int IndexOf(object value)
{
    return Array.IndexOf((Array)_items, value, 0, _size); // value 裝箱
}

LinkedList<T>:雙向鏈表的教科書級實現


[Serializable]
public class LinkedList<T> : ICollection<T>, ICollection, ISerializable, IDeserializationCallback
{
    internal LinkedListNode<T> head;
    internal int count;
    internal int version;
    private object _syncRoot;
    private SerializationInfo siInfo; // 反序列化暫存
    const string VersionName = "Version", CountName = "Count", ValuesName = "Data";
    ...
}

核心設計亮點

  1. 節點封裝:LinkedListNode<T> 內含 Prev/Next/List/Value,所有操作 (AddFirst/Last/Before/After) 均維護雙向鏈接完整性。
  2. 列舉器支援序列化/反序列化回調:內部類 Enumerator 同時實現 IEnumerator、ISerializable、IDeserializationCallback,確保枚舉狀態可跨應用程式域流動。
  3. 反序列化重建鏈表:利用 IDeserializationCallback.OnDeserialization 在物件圖完全反序列化後,從 SerializationInfo 取出陣列逐項 AddLast 重建鏈結:

public virtual void OnDeserialization(object sender)
{
    if (siInfo == null) return;
    int realVersion = siInfo.GetInt32(VersionName);
    int count = siInfo.GetInt32(CountName);
    if (count != 0)
    {
        T[] array = (T[])siInfo.GetValue(ValuesName, typeof(T[]));
        foreach (T item in array) AddLast(item);
    }
    else head = null;
    version = realVersion;
    siInfo = null;
}

此模式優於四大序列化回調屬性 (OnDeserializedAttribute 等),因能確保依賴圖中其他物件已就緒。

對比總結與實務啟示

維度ArrayListLinkedList<T>
層級CLR BCL 核心FX 擴展組件
資料結構動態陣列雙向鏈表
型別安全無 (object)泛型強型別
隨機存取O(1)O(n)
插入/刪除O(n) 位移O(1) 節點操作
序列化支援ICloneable (淺複製)ISerializable + IDeserializationCallback (完整圖重建)
列舉器穩定性_version 機制_version + 節點引用驗證

給開發者的建議

  • 新專案首選 List<T>:型別安全、無裝箱、效能優於 ArrayList。
  • 需頻繁首尾插刪、不需隨機存取:考慮 LinkedList<T>。
  • 避免使用 ArrayList:除非維護 .NET 1.x 遺留代碼或需與非泛型 API 互操作。
  • 序列化鏈表/圖結構:參考 LinkedList 的 ISerializable + IDeserializationCallback 模式,在 OnDeserialization 中重建引用關係,比單純屬性回調更可靠。

微軟源碼並非神秘黑盒,其實現邏輯與我們自行編寫集合類別時的思路高度一致,差異在於邊界處理、介面契約履行、序列化穩健性等工程細節上的打磨。閱讀源碼,重在學習這些「專業細節」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved