2012-11-30 45 views
0

我想做一些數組傳遞給.NET函數,我有點困惑。數組是引用類型,因此對傳遞給該函數的數組所做的更改在函數外部是可見的。例如傳遞數組的功能有或沒有參考關鍵字

static void Main(string[] args) 
{ 
    byte[] arr = new byte[] { 1,2, 3, 4, 5 };  
    Console.WriteLine(string.Join("", arr));  //console output: 12345 
    doSomething(arr); 
    Console.WriteLine(string.Join("", arr));  //console output: 52341 
} 
static void doSomething(byte[] array) 
{ 
    byte tmp = array[0]; 
    array[0] = array[array.Length - 1]; 
    array[array.Length - 1] = tmp; 
} 

所以它的工作原理完全一樣,與(同一控制檯輸出)

doSomething(ref arr); for static void doSomething(ref byte[] array) 

但是用「裁判」的關鍵字,如果我添加下面一行到我的功能:

array = (new byte[] { 1 }).Concat(array).ToArray(); //size of array is changed 

結果是不同的:

12345 
52341// "ref" keyword is not used 

12345 
152341 "ref" keyword is used 

有人能解釋我爲什麼結果不同嗎?

+0

[參數傳遞在C#](http://www.yoda.arachsys.com/csharp/parameters.html#ref) – sll

回答

2

值類型變量是包含值的變量。 arr是指向內存中byte []的一個實例的對象變量。當您通過值傳遞給方法doSomething時,您正在傳遞一個指向內存中byte []的實例的指針。這樣,arr和array都指向內存中byte []的同一個實例。如果DoSomething更改了arr和array所指向的byte []實例,它實際上並不會更改變量arr,因爲它仍然指向內存中的相同位置。但是,由於arr仍然指向內存中的相同位置,並且該位置的實例已更新,則arr可以「看到」更改。

當你調用Concat時,它會在內存中的其他地方生成一個新的byte []實例,並且它將變量數組poitns到內存中的新實例。 byte []的舊實例仍然存在,並且arr仍然指向它。

當通過REF傳遞變量ARR,然後到陣列指向也會影響其中ARR指向任何變化。當它不通過參考DoSomething只能更改內存中的字節[]的實例,指向,但它不能更改,其中指向。

這就是爲什麼按引用傳遞對象和按值傳遞對象之間存在差異的原因。

+0

謝謝,這似乎是非常合乎邏輯的,我想我有點困惑,因爲價值和參考類型。只是爲了確保我理解 - 值類型可以作爲值(例如4)傳遞,並作爲參考與「ref」一起使用(例如,「放置在放置4的內存中的」種類「指針) - 引用類型(例如,數組,類)可以作爲引用傳遞給它自我(例如「放置在放置數組/類的內存中的指針類型」)或作爲對引用的引用 – user1049522

0

對於在方法中傳遞的任何參數沒有Ref關鍵字 - 創建的局部變量並代表原始參數的副本。所以當你傳入引用類型變量arr時 - 這是真正的Int32引用,指向某個地址,比如ADDR。然後在一個方法中創建這個變量的副本,它與原始參數(arr)完全無關。但仍指向內存中的相同地址,您仍然可以更改基礎原始數據。當您通過分配= new ...來更改參考值本身時,參考值的本地副本會發生更改,但此更改不會影響方法中傳遞的原始參考值。

如果你想「綁定」原件備查,並在方法創建一個新的new() - 使用Ref,通過指定Ref你說「我想通過/傳遞給參考參考」。

以下線之後:

array = (new byte[] { 1 }).Concat(array).ToArray(); 
  • Ref參數情形:參考改變,但是,因爲它是通過引用傳遞(Ref) - 原始參考的影響以及
  • 在默認參數傳遞的情況下:本地參考副本被更改,但原始不受影響,因此您獲得了指向新創建陣列的新參考號