1、首先來解釋一下C#中的類型
在C#中每一種類型要麼是值類型,要麼是引用類型。所以每個對象要麼是值類型的實例,要麼是引用類型的實例。並且在C#中對象的分配模式取決於對象的實現方式,即值類型使用靜態分配,引用類型使用動態分配。即便是在進行值類型實例化的時候使用new關鍵字進行實例化也不會改變實例的分配方式,在這種情況下new操作法僅起到向構造函數傳遞參數的作用。
C#中的引用是一個不同於引用類型的概念,它介於C++中的指針和引用之間。可以是一個到對象的引用,所有該對象的可訪問成員都可以通過“.”操作法進行訪問;引用可以爲空;引用可以被修改(這裏要注意在方法參數中使用ref關鍵字的結果) ;不能夠訪問對象的物理空間,即對象的實際地址。
2、引用類型和值類型代碼示例
- //TypeVal 是值類型,因爲它是一個結構體
- struct TypeVal
- {
- public int _i;
- public TypeVal(int i) { _i = i; }
- }
- //TypeRef 引用類型
- class TypeRef
- {
- public int _i;
- public TypeRef(int i) { _i = i; }
- }
- class Program
- {
- static void Main()
- {
- //創建一個值類型的實例
- TypeVal v1 = new TypeVal(6);
- //此處創建一個新的TypeVal類型的實例,v1和v2是兩個不同的對象
- //這兩個對象的實例被保存在當前的線程棧中,一般我們稱之爲變量
- TypeVal v2 = v1;
- v2._i = 10;
- //
- System.Diagnostics.Debug.Assert(v1._i == 6 && v2._i == 9);
- //創建一個 TypeRef 的對象,該語句實際上創建了一個存放於進程堆中的對象
- //r1本身存在於線程棧上,r1實際上是對新創建對象的引用
- TypeRef r1 = new TypeRef(6);
- //r2引用了r1所引用的對象,即一個實際的對象實例,兩個指向對象的引用
- TypeRef r2 = r1;
- r2._i = 11;
- System.Diagnostics.Debug.Assert(r1._i == 11 && f2._i == 11);
- }
- }
3、在方法中修改引用類型的範例
- class RefTest
- {
- public int Number = 0;
- //使用ref 關鍵字相當於C++中的雙指針
- //按照引用類型ref 傳遞引用類型參數允許主調方法直接操作引用,即被調用的方法能夠修改
- //主調方法的的引用所引用的對象。
- public static void fct(ref RefTest RefA, RefTest RefB)
- {
- if (RefA == null)
- RefA = new RefTest();
- if (RefB == null)
- RefB = new RefTest();
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- f_RefTest();
- }
- static void f_RefTest()
- {
- RefTest refA = null;
- RefTest refB = null;
- RefTest.fct(ref refA, refB);
- if (refA == null)
- System.Console.WriteLine("refA is null");
- else
- System.Console.WriteLine("refA now references the RefTest allocated in fct");
- if (refB == null)
- System.Console.WriteLine("refB is null");
- else
- System.Console.WriteLine("refB now references the RefTest allocated in fct");
- System.Console.ReadLine();
- }
輸出結果如下:
可見對於添加ref關鍵字的引用類型,其效用就在於能夠在方法內部對引用的指向進行修改。如果不添加ref關鍵字,那麼其作用僅限於通過引用修改該引用所指向的對象的內部狀態(對象的字段等)。
4、ref 與string
C#中string類具有三大特點,即sealed、等價比較、實例創建後的不可變性。
- static void TestString(ref string str1, string str2)
- {
- //此處創建了一個新的string實例,並修改了str1引用的指向
- str1 = "new str1";
- //創建一個新的string實例,在方法內部修改str2的引用
- str2 = "new str2";
- }
- static void Main(string[] args)
- {
- //f_RefTest();
- string str1 = "str1";
- string str2 = "str2";
- TestString(ref str1, str2);
- Console.WriteLine(str1);
- Console.WriteLine(str2);
- Console.ReadLine();
- }
5、總結
ref(引用型參數)對方法的數據傳遞是通過實際值的內存地址來傳遞的,所以說對其的改變將影響到它實際的內存地址。如果ref 作用於引用類型,那麼意味着可以修改引用本身的值,即修改引用的指向。