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

c#引用傳遞和值傳遞

編輯:C#入門知識

我們知道,c#的數據類型分為值類型和引用類型。值類型包括基本類型(數值類型,bool類型等)、結構和枚舉,引用類型包括類、委托、數組等。在使用方法傳遞變量時,就需要了解值類型和引用類型作為參數傳遞的機制了。

    先看下面一段代碼:

   

namespace ConsoleApplication1 

    class Program 
    { 
        static void Main(string[] args) 
        { 
            int aNumber = 10; 
            A a = new A(); 
            a.Name = "aaaaaaaa"; 
            Console.WriteLine(aNumber); 
            Console.WriteLine(a.Name); 
            ToDouble(aNumber); 
            ToDouble(a); 
            Console.WriteLine(aNumber); 
            Console.WriteLine(a.Name); 
            Console.ReadKey(); 
        } 
        static void ToDouble(int number) 
        { 
            number *= 2; 
        } 
        static void ToDouble(A a) 
        { 
            a.Name += "ssssssss"; 
        } 
    } 
    class A 
    { 
        private string name; 
        public string Name 
        { 
            get { return name; } 
            set { name = value; } 
        } 
    } 

 

    輸出結果為:

    10

    10

    10

    1010

    通過結果發現,值類型aNumber在經過函數處理後,再次輸出時值並沒有發生變化,而引用類型class A的屬性發生了變化,為什麼會發生這種情況?

    數據類型在內存中的保存時,值類型保存在堆棧中,引用類型將它的值保存在托管堆中,在堆棧中保存的是對堆上地址的引用,在方法中傳遞參數時,所有類型都是傳遞堆棧中的位置,具體過程為先在堆棧上復制一個傳遞的對象,然後將該對象傳給參數,所以顯而易見,數值類型保存在堆棧中,作為參數傳遞時直接復制了數值的一個副本給方法,方法對該副本所做的任何操作都不會影響到該數值的原值,但是引用類型復制的是堆棧上對堆的引用,該引用指向的仍然是堆上的引用類型,所以對應用類型所做的操作都會引起其本身的改變。

    下面我們再看一段代碼:

   

namespace ConsoleApplication1 

    class Program 
    { 
        static void Main(string[] args) 
        { 
            string aStr="10"; 
            Console.WriteLine(aStr); 
            ToDouble(aStr); 
            Console.WriteLine(aStr); 
            Console.ReadKey(); 
        } 
        static void ToDouble(string aStr) 
        { 
            aStr+=aStr; 
        } 
    } 

 

    輸出結果為:

    10

    10

    string類型是引用類型,所以在方法中傳遞的仍然是堆棧中對string變量引用的副本,但是為什麼上面的代碼並沒有改變string變量的值呢?這裡我們就需要知道,在c#中,string是一個比較特殊的類型,微軟並不提倡我們些如下的代碼:

   

namespace ConsoleApplication1 

    class Program 
    { 
        static void Main(string[] args) 
        { 
          string aStr="aaaaa"; 
          string aOtherStr="bbbbb"; 
          string theyConcat=aStr+aotherStr; 
        } 
    } 

 

    上面的代碼首先聲明了一個變量aStr,然後將其與另一個字符串連接,在具體實現過程中,系統先在托管對中保存了aaaaa值,在進行連接運算時,先將aaaaa的值復制一份,然後在後面連接bbbbb,最後將得到的新值的地址賦給aStr,所以此時aaaaa並沒有在內存中刪除,直到垃圾回收器將其回收。比較好的做法是在需要進行連接字符串操作時,使用StringBulider類進行操作,它會直接在對象後面進行連接操作,而不會先將值復制一遍。

    回到上面的方法來,當String類型作為參數傳遞時,系統會先在托管堆中將值復制一遍,堆棧上得到的地址指向這個新值,所以方法對string類型的操作並不影響到它的原有值。

    這裡我們必然會想到,如果我需要使用一個方法改變值類型的值咋辦呢?比如說,當我們需要一個方法輸出多個值時,我們知道,當方法有返回值時,最後return回來的總是只有一個值,如果我需要將參數a、b同時傳入方法並得到兩個結果時,怎麼辦呢?此時就需要使用引用傳遞了。c#的方法使用了ref關鍵字,該關鍵字表示將參數作為引用類型傳遞,看下面的代碼:

   

class Program 
   { 
       static void Main(string[] args) 
       { 
           int a = 10; 
           int b = 50; 
           Console.WriteLine(a); 
           Console.WriteLine(b); 
           ToDouble(ref a,ref b); 
           Console.WriteLine(a); 
           Console.WriteLine(b); 
           Console.ReadKey(); 
       } 
       static void ToDouble(ref int a,ref int b) 
       { 
           a *= 2; 
           b *= 2; 
       } 
   } 
 

    輸出結果:

    10

    50

    20

    100

    通過這個方法,我們同時改變了a和b的值。

摘自 魯信的專欄
 

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