首先提一下,個人在項目中已經很少用到數組了,更多的時候使用List<>。
數組大小固定,如果只是用來存放數據,專門用來讀取,更改當然方便。但是更多的時候我們需要進行增刪改,這個時候用List<>反而更好。
所有數組類型都從System.Array抽象類隱式派生,後者又派生自System.Object。
一個數組的誕生
String[] arr=String[10];
當執行上述語句時,CLR會自動為AppDomain創建一個String[]類型。該類型隱式派生自System.Array,所以它可以用System.Array中定義的方法。
而所有的數組都隱式實現IEnumerable,ICollection和IList,因為System.Array也實現這三個接口。
並且當創建的是一維0基數組類型,CLR會自動使數組類型實現當前IEnumerable,ICollection和IList這三個接口的基於基礎類型及其基類(這裡的基礎類型就是指String和它的基類Object)的泛型玩法,
即IEnumerable<String>,ICollection<String>和IList<String>,IEnumerable<Object>,ICollection<Object>和IList<Object>.(而System.Array是不實現的,因為涉及到多維數組和非0基數組)。這裡說的0基數組是指數組索引以0開始開始的數組。
然而如果數組的基礎類型是值類型,即int[]這種,是不會實現泛型接口的,只會實現那三個非泛型接口。
數組始終是引用類型,所以會在堆上分配,而不是像c一樣在棧上分配。
創建引用類型數組,實際上創建的只是一個裝滿了引用的數組,而具體引用類型並沒有被創建,這些引用默認為null。
三種數組
通常來講我們會用到以下三種數組:
int[] 一維數組 = new int[5]; int[,] 多維數組 = new int[3, 4]; int[][] 交錯數組 = new int[2][]; 交錯數組[0] = new int[10]; 交錯數組[1] = new int[100];
數組的類型轉換
數組的也可以轉換基礎類型,比如將String[]類型就可以轉換為Object[]類型。
但是轉型要求數組維數相同,且CLR不允許將值類型的數組轉化為任何類型。(但是可以用Array.Copy來實現值類型數組的轉換)
如果只是需要將一個數組中的某些元素復制到另一個同類型數組中,那麼可以考慮System.Buffer的BlockCopy方法,一看這些奇怪的名字就知道是底層操作,它比Array.Copy快。但是它不能像Array.Copy那樣提供轉型能力,比如將Object[]轉成Int[].
數組的傳遞和返回
數組作為參數來傳遞,實際上傳遞的只是數組的引用。
如果定義了返回數組引用的方法,而且數組中不包含元素,那麼就可以返回null,但是推薦返回new int[0]這樣的東西。
創建非0基數組
老實說本來不打算寫的,確實搞不清楚哪裡要用到這種東西,如果用來增加代碼閱讀難度,為了裝B強行寫垃圾代碼倒是個不錯的選擇。
Array.CreateInstance這個方法即可,不過這個方法感覺用來動態地創建數組不錯。其實知道就行了,一般也用不到,List<>簡單方便多了。
有下限的數組和下限未知的數組
CLR支持兩類數組,一類是一維0基數組,一類是下限未知的一維數組和多維數組
一般看數組的類型,比如0基數組的類型就是System.String[],非0基數組的類型為System.String[*].
訪問一維0基數組的元素比非0基或多維數組的元素稍快。因為有一些特殊IL指令處理一維0基數組,會導致JIT編譯器生成優化代碼。
所以其實交錯數組實際上是多個一維數組,也比多維數組的處理更快,所以也可以用交錯數組去替代多維數組去提高性能。
PS:
《CLR via C#》這章還介紹了如何去用不安全的方式去操作數組:
可以將數組不作為引用對象而是直接嵌入結構內部,
也可以用stackalloc語句去在線程棧上分配數組,而不是像之前一樣在堆上分配數組。
然而這種方式一般也就知道就好,主要用來和非托管代碼進行互操作。
因為是用unsafe方式啊,反正不到逼不得已我連想都不會想起來,麻煩,也不完全。