第六講 方法
方法又稱成員函數(Member Function),集中體現了類或對象的行為。方法同樣分為靜態方法和實例方法。靜態方法只可以操作靜態域,而實例方法既可以操作實例域,也可以操作靜態域--雖然這不被推薦,但在某些特殊的情況下會顯得很有用。方法也有如域一樣的5種存取修飾符--public,protected,internal,protected internal,private,它們的意義如前所述。
方法參數
方法的參數是個值得特別注意的地方。方法的參數傳遞有四種類型:傳值(by value),傳址(by reference),輸出參數(by output),數組參數(by array)。傳值參數無需額外的修飾符,傳址參數需要修飾符ref,輸出參數需要修飾符out,數組參數需要修飾符params。傳值參數在方法調用過程中如果改變了參數的值,那麼傳入方法的參數在方法調用完成以後並不因此而改變,而是保留原來傳入時的值。傳址參數恰恰相反,如果方法調用過程改變了參數的值,那麼傳入方法的參數在調用完成以後也隨之改變。實際上從名稱上我們可以清楚地看出兩者的含義--傳值參數傳遞的是調用參數的一份拷貝,而傳址參數傳遞的是調用參數的內存地址,該參數在方法內外指向的是同一個存儲位置。看下面的例子及其輸出:
using System; class Test { static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; } static void Swap(int x,int y) { int temp = x; x = y; y = temp; } static void Main() { int i = 1, j = 2; Swap(ref i, ref j); Console.WriteLine("i = {0}, j = {1}", i, j); Swap(i,j); Console.WriteLine("i = {0}, j = {1}", i, j); } }
程序經編譯後執行輸出:
i = 2, j = 1 i = 2, j = 1
我們可以清楚地看到兩個交換函數Swap()由於參數的差別--傳值與傳址,而得到不同的調用結果。注意傳址參數的方法調用無論在聲明時還是調用時都要加上ref修飾符。
籠統地說傳值不會改變參數的值在有些情況下是錯誤的,我們看下面一個例子:
using System; class Element { public int Number=10; } class Test { static void Change(Element s) { s.Number=100; } static void Main() { Element e=new Element(); Console.WriteLine(e.Number); Change(e); Console.WriteLine(e.Number); } }
程序經編譯後執行輸出:
10 100
我們看到即使傳值方式仍然改變了類型為Element類的對象t。但嚴格意義上講,我們是改變了對象t的域,而非對象t本身。我們再看下面的例子:
using System; class Element { public int Number=10; } class Test { static void Change(Element s) { Element r=new Element(); r.Number=100; s=r; } static void Main() { Element e=new Element(); Console.WriteLine(e.Number); Change(e); Console.WriteLine(e.Number); } }
程序經編譯後執行輸出:
10 10
傳值方式根本沒有改變類型為Element類的對象t!實際上,如果我們能夠理解類這一C#中的引用類型(reference type)的特性,我們便能看出上面兩個例子差別!在傳值過程中,引用類型本身不會改變(t不會改變),但引用類型內含的域卻會改變(t.Number改變了)!C#語言的引用類型有:object類型(包括系統內建的class類型和用戶自建的class類型--繼承自object類型),string類型,interface類型,array類型,delegate類型。它們在傳值調用中都有上面兩個例子展示的特性。