程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 把c#中的Array說透

把c#中的Array說透

編輯:C#入門知識

1. 數組大局觀

數組是一個引用類型,也就是意味著數組的內存分配在托管堆上,並且我們在棧上維護的是他的指針而並非真正的數組。

接下來我們分析下數組的元素,其中的元素無外乎是引用類型和值類型。

當數組中的元素是值類型時,,不同於int i;這樣的代碼。數組會根據數組的大小自動把元素的值初始化為他的默認值。例如:

static void Main(string[] args)
{
    int[] intArray = new int[3];
    foreach(int i in intArray)
    {
        Console.WriteLine(i);
    }
    DateTime[] dtArray = new DateTime[3];
    foreach (DateTime i in dtArray)
    {
        Console.WriteLine(i);
    }
}

結果如下:

image

當數組中的元素是引用類型時,實際上數組中的元素是一個指向對象實際內存空間的指針,占用4Bytes的空間。

2. 談談零基數組

從學C語言時起,相信老師就會對我們講,數組的第一個索引是0,而不是1。但是在C#中,我們可以去構造一個非零基數組,在這一節,我們就來把這個說透。

在常規意義上,我們初始化一個數組,都默認是零基數組,這也使得數組成為了字符串後再一個初始化時特殊的類型。正如我們知道的一樣,初始化一個字符串時,對應的IL指令是newstr,同樣,初始化一個零基數組對應的IL指令是newarr。

當我們希望構造一個非零基數組時,我們可以以下的語句來做到:

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

 

得到的測試結果便如下:

image

於是便證明,我們初始化了一個非零基數組。此外,延伸一下,我們還應該通過這個記住以下兩個方法:

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

 

得到的測試結果如下:

image

3. 談談效率問題

相信會有好多陰謀論者說,C#是個類型安全的語言,也就是意味著我循環時每次訪問一次數組的元素,那麼就要檢查一次該索引是否會造成數組越界,於是就造成了一定的性能損失。那麼在這裡,我們就把這個問題說透。

我們在這裡把數組分成零基數組,非零基數組,多維數組,交錯數組四種情況來分別討論這個問題。

零基數組是.NET中提倡使用的類型,並且初始化時提供了特殊的IL指令newarr則充分說明了他在.NET中的特殊性,自然.NET Framework也會為其提供很大的優化待遇。在循環訪問數組時,如這樣的代碼:

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

 

JIT編譯器只會在循環開始之前檢查一次4和intArr.GetUpperBound的大小關系,之後便不會對其進行干預。也就是說JIT編譯器只對其檢查一次安全,因此帶來的性能損失是非常小的。

而對於非零基數組,我們來比較這樣兩段代碼:

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

 

其實兩者創建的幾乎是相同的數組,調用的也幾乎是一樣的方法,但是我們看下IL卻會發現兩者有著驚人的不同,首先是非零基數組的IL:

image

接下來是零基數組的:

image

我們可以發現,對於非零基數組中的大部分操作,.NET Framework都提供了對應的IL指令,我們也可以理解為.NET Framework為其提供了特殊的優化。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved