.NET Framework源碼研究系列之—ArrayList與LinkedList

來源:互聯網
上載者:User

  在上一篇<.NET Framework源碼研究系列之---馬甲List>中我們一起研究了.NET中List的原始碼,也得到一些兄弟的熱心反饋.其中一位仁兄說希望看到ArrayList與LinkedList原始碼,所以今天就以此為話題,大家一起看一下.NET中是如何?ArrayList和LinkedList的.

  我們先看ArrayList和LinkedList在.NET中的位置,ArrayList的命名空間是System.Collections,LinkedList的命名空間是System.Collections.Generic,這麼看來二者同屬於集合類,只不過LinkedList在一個分支種.然而,稍對.NET的源碼分析後,我們會發現二者有著明顯的區別,甚至可以說有質的不同.有這些不同不是因為二者功能的不同,而是微軟對它們的定位不同.在.NET源碼物理結構中,ArrayList所在目錄是"redbits\ndp\clr\src\BCL\System\Collections",LinkedList所在目錄是"redbits\ndp\fx\src\CompMod\System\Collections\Generic".由此可知,ArrayList屬於CLR層級的,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];

以上是ArrayList中包含的欄位.看過<.NET Framework源碼研究系列之---馬甲List>是的兄弟是不是覺得很眼熟呢?

  是的,其實ArrayList與List一樣.二者同屬於CLR基礎類,實現過程幾乎一模一樣.但是二者還是有細節的不同.

  首先,ArrayList是無類型約束的,也就是說ArrayList中可以包含任何類型;而List是強型別的.雖然二者本質上都是調用Array的靜態方法,如Copy,但在某些方法中ArrayList需要進行裝箱拆箱的操作,由此會帶來部分效能損失,如下代碼:

        public virtual int IndexOf(Object value){
return Array.IndexOf((Array)_items, value, 0, _size);
}

  其次,ArrayList繼承了ICloneable介面,而List沒有.如下.

代碼

        public virtual Object Clone(){
ArrayList la = new ArrayList(_size);
la._size = _size;
la._version = _version;
Array.Copy(_items, 0, la._items, 0, _size);
return la;
}

 

 

由上面代碼我們可以看出ArrayList實現的時淺拷貝.這裡有個疑惑就是微軟對ArrayList實現複製介面的初衷,為是淺拷貝而不是深拷貝.

 

  比較ArrayList和List原始碼後,我大致總結出二者主要有以上的不同.接下來我們看LinkedList.

  仍舊先看定義:

代碼

    public class LinkedList<T> : ICollection<T>, System.Collections.ICollection, ISerializable, IDeserializationCallback{
internal LinkedListNode<T> head;
internal int count;
internal int version;
private Object _syncRoot;
//還原序列化時用到的一個臨時變數
private SerializationInfo siInfo;
/*序列化名字*/
const String VersionName = "Version";
const String CountName = "Count";
const String ValuesName = "Data";

public LinkedList(){}
public LinkedList(IEnumerable<T> collection){
if (collection == null){
throw new ArgumentNullException("collection");
}

foreach (T item in collection){
AddLast(item);
}
}
protected LinkedList(SerializationInfo info, StreamingContext context){ siInfo = info; }

LinkedList實現了ICollection介面,說明它是個集合類.實現ISerializable介面說明它預設支援序列化,另外還隱藏實現了IEnumerable介面.最後還支援一個比較少用的介面IDeserializationCallback,該介面使LinkedList在完成還原序列化前可以執行一定的動作.

  LinkedList對ICollection,ISerializable我們並不奇怪,在實現IEnumerable時有點稍許的不同.與ArralyList,List相同的時,在現實IEnumerable時LinkedList一樣是使用了一個內部類Enumerator,與ArralyList,List不同的是Enumerator在實現IEnumerator,ISerializable時也實現了IDeserializationCallback介面.另外就是對IEnumerator.MoveNext方法的實現不同.這是因為LinkedList是雙向鏈表,集合中每個元素的分配空間並不連續,需要通過前後的引用來擷取.我們沒向LinkedList添加一個對象的時候,LinkedList實際上會將我們添加的對象封裝為LinkedListNode對象,而該對象就有Prev和Next兩個屬性.這點相信大家都很容易理解.

  剛才我們說到LinkedList還實現了IDeserializationCallback介面,對於這點,需要有以下2點說明.第一,就如上面介紹IEnumerable介面一樣,它這麼做是因為在還原序列化的時候要維護集合中元素的前後引用;第二,要達到此類目的也可以使用另一個方法.我們知道,其實.NET中每個可序列化的類預設都支援以下四個方法:

  OnDeserialized//還原序列化完成時執行的方法

  OnDeserializing//還原序列化時執行的方法

  OnSerialized//序列化完成時執行的方法

  OnSerializing//序列化時執行的方法

通過這4個方法,我們就可以做很多事情,比如序列化本來不可序列化的對象.LinkedList的欄位private SerializationInfo siInfo;其實就是OnDeserialized使用的.大家來看下LinkedList是如何?該方法的:

代碼

        public virtual void OnDeserialization(Object sender){
if (siInfo == null){
return; //Somebody had a dependency on this Dictionary and fixed us up before the ObjectManager got to it.
}

int realVersion = siInfo.GetInt32(VersionName);
int count = siInfo.GetInt32(CountName);

if (count != 0){
T[] array = (T[])siInfo.GetValue(ValuesName, typeof(T[]));

if (array == null){
throw new SerializationException(SR.GetString(SR.Serialization_MissingValues));
}
for (int i = 0; i < array.Length; i++){
AddLast(array[i]);
}
}
else{
head = null;
}
version = realVersion;
siInfo = null;
}

其實用過LinkeList的人都知道LinkedList是一個雙向鏈表,也是個集合.如果讓大家各自實現一個相同的鏈表,實現過程其實都差不多.微軟版LinkedList的實現也與大家一樣,區別的地方也就是上面提到的地方.作為集合,LinkedList對ICollection介面的實現與ArrayList一樣;作為鏈表,在實現ICollection介面,和其他一些專屬的方法時要著重維護鏈表中每個元素的Prev和Next兩個屬性.實現代碼這裡就不一一列出了.

 

小結  

      經過上一篇<.NET Framework源碼研究系列之---馬甲List>和本篇,我覺得其實微軟的東西並不神秘,做同樣一件事,不管思維過程,還是實現手法,跟我們都差不多.區別更多的在於細節,如對IEnumerable的實現方法,對 IDeserializationCallback的選擇.在我們實際工作的,可以參考微軟的做法,也可以按我們自己的方法來,其實沒有質的不同.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.