C# 引用類型與ref

 1、首先來解釋一下C#中的類型

     在C#中每一種類型要麼是值類型,要麼是引用類型。所以每個對象要麼是值類型的實例,要麼是引用類型的實例。並且在C#中對象的分配模式取決於對象的實現方式,即值類型使用靜態分配,引用類型使用動態分配。即便是在進行值類型實例化的時候使用new關鍵字進行實例化也不會改變實例的分配方式,在這種情況下new操作法僅起到向構造函數傳遞參數的作用。

     C#中的引用是一個不同於引用類型的概念,它介於C++中的指針和引用之間。可以是一個到對象的引用,所有該對象的可訪問成員都可以通過“.”操作法進行訪問;引用可以爲空;引用可以被修改(這裏要注意在方法參數中使用ref關鍵字的結果) ;不能夠訪問對象的物理空間,即對象的實際地址。

2、引用類型和值類型代碼示例

  

[c-sharp] view plain copy
  1. //TypeVal 是值類型,因爲它是一個結構體  
  2. struct TypeVal  
  3. {  
  4.     public int _i;  
  5.     public TypeVal(int i) { _i = i; }  
  6. }  
  7. //TypeRef 引用類型  
  8. class TypeRef  
  9. {  
  10.     public int _i;  
  11.     public TypeRef(int i) { _i = i; }  
  12. }  
  13.   
  14. class Program  
  15. {  
  16.     static void Main()  
  17.     {  
  18.         //創建一個值類型的實例  
  19.         TypeVal v1 = new TypeVal(6);  
  20.         //此處創建一個新的TypeVal類型的實例,v1和v2是兩個不同的對象  
  21.         //這兩個對象的實例被保存在當前的線程棧中,一般我們稱之爲變量  
  22.         TypeVal v2 = v1;  
  23.   
  24.         v2._i = 10;  
  25.         //  
  26.         System.Diagnostics.Debug.Assert(v1._i == 6 && v2._i == 9);  
  27.   
  28.         //創建一個 TypeRef 的對象,該語句實際上創建了一個存放於進程堆中的對象  
  29.         //r1本身存在於線程棧上,r1實際上是對新創建對象的引用  
  30.         TypeRef r1 = new TypeRef(6);  
  31.         //r2引用了r1所引用的對象,即一個實際的對象實例,兩個指向對象的引用  
  32.         TypeRef r2 = r1;  
  33.   
  34.         r2._i = 11;  
  35.   
  36.         System.Diagnostics.Debug.Assert(r1._i == 11 && f2._i == 11);  
  37.     }  
  38. }  

3、在方法中修改引用類型的範例

 

[c-sharp] view plain copy
  1. class RefTest  
  2. {  
  3.     public int Number = 0;  
  4.   
  5.     //使用ref 關鍵字相當於C++中的雙指針  
  6.     //按照引用類型ref 傳遞引用類型參數允許主調方法直接操作引用,即被調用的方法能夠修改  
  7.     //主調方法的的引用所引用的對象。  
  8.     public static void fct(ref RefTest RefA, RefTest RefB)  
  9.     {  
  10.         if (RefA == null)  
  11.             RefA = new RefTest();  
  12.         if (RefB == null)  
  13.             RefB = new RefTest();  
  14.     }  
  15. }  
  16.   
  17.   
  18. class Program  
  19. {  
  20.     static void Main(string[] args)  
  21.     {  
  22.         f_RefTest();  
  23.     }  
  24.     static void f_RefTest()  
  25.     {  
  26.         RefTest refA = null;  
  27.         RefTest refB = null;  
  28.         RefTest.fct(ref refA, refB);  
  29.   
  30.         if (refA == null)  
  31.             System.Console.WriteLine("refA is null");  
  32.         else  
  33.             System.Console.WriteLine("refA now references the RefTest allocated in fct");  
  34.         if (refB == null)  
  35.             System.Console.WriteLine("refB is null");  
  36.         else  
  37.             System.Console.WriteLine("refB now references the RefTest allocated in fct");  
  38.   
  39.         System.Console.ReadLine();  
  40.     }  

輸出結果如下:

可見對於添加ref關鍵字的引用類型,其效用就在於能夠在方法內部對引用的指向進行修改。如果不添加ref關鍵字,那麼其作用僅限於通過引用修改該引用所指向的對象的內部狀態(對象的字段等)。

4、ref 與string

C#中string類具有三大特點,即sealed、等價比較、實例創建後的不可變性。

[c-sharp] view plain copy
  1. static void TestString(ref string str1, string str2)  
  2. {  
  3.   
  4.     //此處創建了一個新的string實例,並修改了str1引用的指向  
  5.     str1 = "new str1";  
  6.     //創建一個新的string實例,在方法內部修改str2的引用  
  7.     str2 = "new str2";  
  8. }  
  9.   
  10. static void Main(string[] args)  
  11. {  
  12.     //f_RefTest();  
  13.   
  14.     string str1 = "str1";  
  15.     string str2 = "str2";  
  16.   
  17.     TestString(ref str1, str2);  
  18.   
  19.     Console.WriteLine(str1);  
  20.     Console.WriteLine(str2);  
  21.     Console.ReadLine();  
  22. }  

 

 

 

5、總結

ref(引用型參數)對方法的數據傳遞是通過實際值的內存地址來傳遞的,所以說對其的改變將影響到它實際的內存地址。如果ref 作用於引用類型,那麼意味着可以修改引用本身的值,即修改引用的指向。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章