自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳解.NET數(shù)組的前世今生

開(kāi)發(fā) 后端
在這里我們將把.NET數(shù)組講透,包括多維數(shù)組和交錯(cuò)數(shù)組,希望對(duì)大家了解Array有所幫助。

Array也就是數(shù)組,本文將為大家講述的是.NET數(shù)組的前生今世,希望通過(guò)本文能為大家講透.NET數(shù)組。以及數(shù)組的具體使用方法。

1. 數(shù)組大局觀

數(shù)組是一個(gè)引用類(lèi)型,也就是意味著數(shù)組的內(nèi)存分配在托管堆上,并且我們?cè)跅I暇S護(hù)的是他的指針而并非真正的數(shù)組。

接下來(lái)我們分析下數(shù)組的元素,其中的元素?zé)o外乎是引用類(lèi)型和值類(lèi)型。

當(dāng)數(shù)組中的元素是值類(lèi)型時(shí),,不同于int i;這樣的代碼。數(shù)組會(huì)根據(jù)數(shù)組的大小自動(dòng)把元素的值初始化為他的默認(rèn)值。例如:

  1. static void Main(string[] args)  
  2. {  
  3.     int[] intArray = new int[3];  
  4.     foreach(int i in intArray)  
  5.     {  
  6.         Console.WriteLine(i);  
  7.     }  
  8.     DateTime[] dtArray = new DateTime[3];  
  9.     foreach (DateTime i in dtArray)  
  10.     {  
  11.         Console.WriteLine(i);  
  12.     }  

結(jié)果如下:

結(jié)果

當(dāng)數(shù)組中的元素是引用類(lèi)型時(shí),實(shí)際上數(shù)組中的元素是一個(gè)指向?qū)ο髮?shí)際內(nèi)存空間的指針,占用4Bytes的空間。

2. 談?wù)劻慊鶖?shù)組

從學(xué)C語(yǔ)言時(shí)起,相信老師就會(huì)對(duì)我們講,數(shù)組的***個(gè)索引是0,而不是1。但是在C#中,我們可以去構(gòu)造一個(gè)非零基數(shù)組,在這一節(jié),我們就來(lái)把這個(gè)說(shuō)透。

在常規(guī)意義上,我們初始化一個(gè)數(shù)組,都默認(rèn)是零基數(shù)組,這也使得數(shù)組成為了字符串后再一個(gè)初始化時(shí)特殊的類(lèi)型。正如我們知道的一樣,初始化一個(gè)字符串時(shí),對(duì)應(yīng)的IL指令是newstr,同樣,初始化一個(gè)零基數(shù)組對(duì)應(yīng)的IL指令是newarr。

當(dāng)我們希望構(gòu)造一個(gè)非零基數(shù)組時(shí),我們可以以下的語(yǔ)句來(lái)做到:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine(intArr.GetValue(1).ToString());  
  5.     Console.WriteLine(intArr.GetValue(0).ToString());  

得到的測(cè)試結(jié)果便如下:

測(cè)試結(jié)果

于是便證明,我們初始化了一個(gè)非零基數(shù)組。此外,延伸一下,我們還應(yīng)該通過(guò)這個(gè)記住以下兩個(gè)方法:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine(intArr.GetLowerBound(0));  
  5.     Console.WriteLine(intArr.GetUpperBound(0));  

得到的測(cè)試結(jié)果如下:

測(cè)試結(jié)果

3. 談?wù)勑蕟?wèn)題

相信會(huì)有好多陰謀論者說(shuō),C#是個(gè)類(lèi)型安全的語(yǔ)言,也就是意味著我循環(huán)時(shí)每次訪問(wèn)一次數(shù)組的元素,那么就要檢查一次該索引是否會(huì)造成數(shù)組越界,于是就造成了一定的性能損失。那么在這里,我們就把這個(gè)問(wèn)題說(shuō)透。

我們?cè)谶@里把數(shù)組分成零基數(shù)組,非零基數(shù)組,多維數(shù)組,交錯(cuò)數(shù)組四種情況來(lái)分別討論這個(gè)問(wèn)題。

零基數(shù)組是.NET中提倡使用的類(lèi)型,并且初始化時(shí)提供了特殊的IL指令newarr則充分說(shuō)明了他在.NET中的特殊性,自然.NET Framework也會(huì)為其提供很大的優(yōu)化待遇。在循環(huán)訪問(wèn)數(shù)組時(shí),如這樣的代碼:

  1. static void Main(string[] args)  
  2. {  
  3.     int[] intArr = new int[5];  
  4.     for (int i = 0; i < 4; i++)  
  5.     {   
  6.         //Some Method  
  7.     }  

JIT編譯器只會(huì)在循環(huán)開(kāi)始之前檢查一次4和intArr.GetUpperBound的大小關(guān)系,之后便不會(huì)對(duì)其進(jìn)行干預(yù)。也就是說(shuō)JIT編譯器只對(duì)其檢查一次安全,因此帶來(lái)的性能損失是非常小的。

而對(duì)于非零基數(shù)組,我們來(lái)比較這樣兩段代碼:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine(intArr.GetValue(1).ToString());  
  5.     Console.WriteLine(intArr.Length);  
  6.     //  
  7.     int[] intArr1 = new int[5];  
  8.     Console.WriteLine(intArr1[1]);  
  9.     Console.WriteLine(intArr1.Length);  

其實(shí)兩者創(chuàng)建的幾乎是相同的數(shù)組,調(diào)用的也幾乎是一樣的方法,但是我們看下IL卻會(huì)發(fā)現(xiàn)兩者有著驚人的不同,首先是非零基數(shù)組的IL:

非零基數(shù)組的IL

接下來(lái)是零基數(shù)組的:

零基數(shù)組

我們可以發(fā)現(xiàn),對(duì)于非零基數(shù)組中的大部分操作,.NET Framework都提供了對(duì)應(yīng)的IL指令,我們也可以理解為.NET Framework為其提供了特殊的優(yōu)化。

當(dāng)然,實(shí)際上,正如CLR via C#所說(shuō)的一樣:.NET Framework對(duì)應(yīng)非零基數(shù)組沒(méi)有任何方面的優(yōu)化,每次訪問(wèn)都需要檢查其上限和下限與索引之間的關(guān)系。效率的損耗是必然的。

事實(shí)上,當(dāng)我們測(cè)試這樣一段代碼時(shí),也會(huì)發(fā)現(xiàn)其實(shí)零基數(shù)組和非零基數(shù)組的區(qū)別是很大的:

  1. static void Main(string[] args)  
  2. {  
  3.     Array intArr = Array.CreateInstance(typeof(Int32), new int[] { 5 }, new int[] { 1 });  
  4.     Console.WriteLine("intArr的?類(lèi)à型í是?:o{0}", intArr.GetType());   
  5.     //  
  6.     int[] intArr1 = new int[5];  
  7.     Console.WriteLine("intArr1的?類(lèi)à型í是?:o{0}", intArr1.GetType());   

得到的結(jié)果如下:

結(jié)果

接下來(lái)我們?cè)賮?lái)簡(jiǎn)單地說(shuō)下多維數(shù)組和交錯(cuò)數(shù)組。

多維數(shù)組和非零基數(shù)組一樣,都沒(méi)有受到.NET Framework的特殊優(yōu)待。

而交錯(cuò)數(shù)組,其實(shí)就是數(shù)組中的數(shù)組,因此效率實(shí)際上取決于數(shù)組中的數(shù)組是零基數(shù)組還是非零基數(shù)組。

那接下來(lái)的一節(jié),我們來(lái)具體探討一下交錯(cuò)數(shù)組和多維數(shù)組的區(qū)別和應(yīng)用。

4. 多維數(shù)組和交錯(cuò)數(shù)組

考慮到兩個(gè)詞的翻譯問(wèn)題,在這里給出兩個(gè)詞的英文:

多維數(shù)組:Multi-dimensional Array。

交錯(cuò)數(shù)組:Jagged Array。

好,下面步入正題。

首先從二者的內(nèi)存分布說(shuō)起。

多維數(shù)組是一個(gè)整體的數(shù)組,因此他在內(nèi)存中占據(jù)一個(gè)整體的托管堆內(nèi)存塊。

而交錯(cuò)數(shù)組實(shí)際上是數(shù)組中的數(shù)組,因此我們用二維交錯(cuò)數(shù)組來(lái)舉例,其內(nèi)存如圖所示:

內(nèi)存圖

也就是說(shuō),如果是一個(gè)3*100的數(shù)組,也就是說(shuō)需要初始化101次數(shù)組,當(dāng)數(shù)組的元素更加多的時(shí)候,那創(chuàng)建和垃圾回收將帶來(lái)巨大的效率損失。

因此,也就是說(shuō):交錯(cuò)數(shù)組的效率瓶頸在于創(chuàng)建和銷(xiāo)毀上,而并非類(lèi)型安全檢查上。

于是,我們就可以得出這樣的結(jié)論:

當(dāng)一次創(chuàng)建,多次訪問(wèn)時(shí),我們應(yīng)該創(chuàng)建交錯(cuò)數(shù)組。

當(dāng)一次創(chuàng)建,一次訪問(wèn)時(shí),我們應(yīng)該創(chuàng)建多維數(shù)組。

5. 用代碼改善效率

上面說(shuō)到了,訪問(wèn)非零基數(shù)組和多維數(shù)組的效率是比較低的,對(duì)于非零基數(shù)組,我們的應(yīng)用比較少,但是多維數(shù)組,相信每個(gè)人都或多或少有著一定的應(yīng)用,那么面對(duì)其性能問(wèn)題,我們?cè)撛趺崔k呢?

我們先來(lái)想想,多維數(shù)組的訪問(wèn),性能瓶頸在安全檢查上。在C語(yǔ)言中,為什么沒(méi)有這樣的問(wèn)題,對(duì),因?yàn)镃語(yǔ)言不會(huì)做這樣的檢查。于是,相信聰明的大家都會(huì)想到不安全代碼。

改善多維數(shù)組以及非零基數(shù)組的效率問(wèn)題,我們就用不安全代碼。

  1. static unsafe void Main(string[] args)  
  2. {  
  3.     int[,] intArr = new int[3, 3];  
  4.     for (int i = 0; i < 3; i++)  
  5.     {  
  6.         for (int j = 0; j < 3; j++)  
  7.         {  
  8.             intArr[i, j] = i * 3 + j;  
  9.         }  
  10.     }  
  11.     fixed (int* p = &intArr[0, 0])  
  12.     {  
  13.         for (int i = 0; i < 3; i++)  
  14.         {  
  15.             int baseOffset = i * 3;  
  16.             for (int j = 0; j < 3; j++)  
  17.             {  
  18.                 Console.WriteLine(baseOffset + j);  
  19.             }  
  20.         }  
  21.     }  

這里,我們又見(jiàn)到了C語(yǔ)言中熟悉的指針,相信不需要多加介紹了。這里唯一需要注意的就是fixed,由于在垃圾回收時(shí)采用的是代機(jī)制+壓縮機(jī)制,因此其內(nèi)存地址很可能發(fā)生改變,因此我們應(yīng)該講數(shù)組的內(nèi)存地址鎖住,防止我們?cè)L問(wèn)到其他的內(nèi)存地址而造成我們讀取數(shù)據(jù)的錯(cuò)誤。

6. 對(duì)零基數(shù)組的精益求精

當(dāng)然,即使是零基數(shù)組,我們依然在托管堆上為其分配了內(nèi)存空間。如果對(duì)性能要求極高,我們知道創(chuàng)建一個(gè)對(duì)象也是有著一定的時(shí)間損耗,其中包括分配內(nèi)存空間,同步塊索引,以及指向下一塊內(nèi)存空間的指針等一系列復(fù)雜的操作。那么我們就放棄掉托管堆這個(gè)東東,而直接在棧中來(lái)創(chuàng)建這個(gè)數(shù)組,這樣又省去了很多時(shí)間,從而達(dá)到了和C語(yǔ)言相同的效果,代碼如下:

  1. static unsafe void Main(string[] args)  
  2. {  
  3.     int* intArr=stackalloc int[10];  
  4.     for (int i = 0; i < 10; i++)  
  5.     {  
  6.         intArr[i] = i;  
  7.     }  
  8.     for (int i = 0; i < 10; i++)  
  9.     {  
  10.         Console.WriteLine(intArr[i]);  
  11.     }  

這樣,效率就進(jìn)一步提高了,對(duì)于二維數(shù)組,我們一樣可以如此創(chuàng)建。其代碼與C語(yǔ)言完全等同。我在這里就不繼續(xù)演示了。

7. 總結(jié)

在全文中,主要是對(duì)數(shù)組的各個(gè)方面做一個(gè)比較簡(jiǎn)略地介紹,其中包括數(shù)組的基礎(chǔ)知識(shí),分類(lèi),以及效率性能問(wèn)題,***就是用不安全代碼來(lái)訪問(wèn)創(chuàng)建數(shù)組來(lái)提高性能。

不過(guò)***說(shuō)一句,在實(shí)際工作中,如果對(duì)性能沒(méi)有特別高的要求,則沒(méi)必要用不安全代碼來(lái)操作數(shù)組,因?yàn)槠浜芸赡芤驗(yàn)槟愕囊恍┦д`而帶來(lái)其他的一些安全問(wèn)題,并且對(duì)代碼的可讀性也是個(gè)比較大的傷害,這就有些得不償失了。

【編輯推薦】

  1. C#數(shù)組基礎(chǔ)介紹與操作詳解
  2. 淺析C#數(shù)組初始化性能測(cè)試
  3. C#數(shù)組操作詳細(xì)剖析
  4. 淺析C#數(shù)組操作方法
  5. C#數(shù)組和串操作經(jīng)驗(yàn)總結(jié)
責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2011-08-23 09:52:31

CSS

2015-11-18 14:14:11

OPNFVNFV

2014-07-30 10:55:27

2025-02-12 11:25:39

2016-12-29 13:34:04

阿爾法狗圍棋計(jì)算機(jī)

2013-05-23 16:23:42

Windows Azu微軟公有云

2014-07-15 10:31:07

asyncawait

2021-06-17 07:08:19

Tapablewebpack JavaScript

2012-05-18 16:54:21

FedoraFedora 17

2014-07-21 12:57:25

諾基亞微軟裁員

2016-12-29 18:21:01

2019-06-04 09:00:07

Jenkins X開(kāi)源開(kāi)發(fā)人員

2016-11-08 19:19:06

2016-11-03 13:33:31

2013-11-14 16:03:23

Android設(shè)計(jì)Android Des

2011-05-13 09:43:27

產(chǎn)品經(jīng)理PM

2019-08-05 10:08:25

軟件操作系統(tǒng)程序員

2019-04-28 09:34:06

2015-06-11 11:10:09

對(duì)象存儲(chǔ)云存儲(chǔ)

2021-04-15 07:01:28

區(qū)塊鏈分布式DLT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)