C#的參數在方法中被使用,是傳值還是傳址?

C#的方法參數中,預設都是傳值,但是有一種情況很容易被乎略並誤用,也就是說,你有可能會以為是傳值(by value),可是事實上是傳址(by reference)才對。

大要要注意一件事,就是在實值類型(Value Types),或稱為基礎型別,例如:int, double...等,套用在方法中的參數都是傳值(by value)沒錯,但是如果傳入的東西已經是物件,那就會變成參考到同一個記憶體位址,這時候就會變成傳址(by reference)了。以下用簡單的程式碼重演這個問題。

using System;

class Program
{
	private static int[] aryTest = {0, 1, 2, 3};

	static void Main()
	{
		disp();
		change(aryTest); //change value
		disp();
	}

	static void change(int[] aryTemp)
	{
		aryTemp[0] = 5;
	}

	static void disp()
	{
		foreach(int temp in aryTest) { Console.Write(temp.ToString()); }
		Console.WriteLine();
	}
}
輸出是:
	0123
	5123

注意重點:

  1. aryTest與aryTemp是參考到同一個記憶體物件的。
  2. static void change(int[] aryTemp)方法中的void並沒有寫錯,沒傳回值的原因是因為你改aryTemp,相當於是改到aryTest的記憶體參考點,因此不需要有傳回值的指定。

下方再舉出一個例子,這裡使用到.NET裡的System.Collection裡面的ArrayList物件,一樣會出現這個問題,藉此提醒使用者注意!

using System;
using System.Collections;

class Program
{
	private static ArrayList myAL = new ArrayList();
	
	static void Main()
	{
		myAL.Add("Hello");
		myAL.Add("World");
		myAL.Add("!");
		disp();
		change(myAL); //change value
		disp();
	}
	
	static void change(ArrayList tempAL)
	{
		tempAL.Remove("World");
	}
	
	static void disp()
	{
		foreach(object oObj in myAL) {
			Console.Write(oObj.ToString());
		}
		Console.WriteLine();
	}
}
輸出是:
	HelloWorld!
	Hello!

但是話說回來啦,如果你是當成By Value的心態,進行鬆藕合的切割觀點來撰寫,也就是傳入與傳出都是真正用ArrayList丟來丟去,老實說除了一次傳址的CPU運算資源外(這個在現代CPU的運算速度觀點來看根本等於0秒),我個人認為並無不會影響到其它的程式運作,在進行程式設計師最愛的Copy-Paste時更顯優勢!下方程式碼多加了回傳ArrayList的觀念範例。(注意!這樣的做法是多餘的,我只是在演譯這樣寫也無妨)

using System;
using System.Collections;

class Program
{
	private static ArrayList myAL = new ArrayList();
	
	static void Main()
	{
		myAL.Add("Hello");
		myAL.Add("World");
		myAL.Add("!");
		disp();
		myAL = change(myAL); //change value
		disp();
	}
	
	static ArrayList change(ArrayList tempAL)
	{
		tempAL.Remove("World");
		return tempAL;
	}
	
	static void disp()
	{
		foreach(object oObj in myAL) {
			Console.Write(oObj.ToString());
		}
		Console.WriteLine();
	}
}
輸出依然是:
	HelloWorld!
	Hello!
CSharp Method Arguments Array Object ByValue ByReference