類型參數與加入ref、out關鍵字的類型參數的區別

 先看例子:

    class TestZhiYin
    {
        static void Main(string[] args)
        {
            int i = 100;
            args ar=new args();
            string str = "One";//特殊的引用類型
            ChangeValueyin(ref i);
            ChangeValueyin(ref ar);
            ChangeStingyin( ref str);
            Console.WriteLine(i);//200
            Console.WriteLine(ar.j);//600
            Console.WriteLine(str);//Two
//            ChangeValuezhi(i);
//            ChangeValuezhi(ar);
//            ChangeStringzhi(str);
//            Console.WriteLine(i);//100
//            Console.WriteLine(ar.j);//600
//            Console.WriteLine(str);//One
        }

        static void ChangeValueyin(ref int iVlaue)
        {
            iVlaue = 200;
            Console.WriteLine(iVlaue);
        }
        static void ChangeValuezhi(int iVlaue)
        {
            iVlaue = 300;
            Console.WriteLine(iVlaue);
        }
        static void ChangeValueyin(ref args ar)
        {
         ar.j=600;
         Console.WriteLine(ar.j);
        }
        static void ChangeValuezhi(args ar)
        {
         ar.j=600;
         Console.WriteLine(ar.j);
        }
        static void ChangeStingyin( ref string sValue)
        {
            sValue = "Two";
            Console.WriteLine(sValue);
        }
        static void ChangeStringzhi(string sValue)
        {
            sValue = "Two";
            Console.WriteLine(sValue);
        }

    }


public class args
{
 public int j=5;
}

 

這裏先說明一下:無論是值類型,還是引用類型不加ref、out關鍵字都是按值傳遞的。值類型傳遞的是值本身的拷貝,引用類型傳遞的是引用本身的拷貝。對值拷貝的操作不會影響到原來的值;對引用拷貝的操作(拷貝引用和原來引用指向同一個對象)可以影響原來的對象,但是特例string除外。

       加上ref、out就是按引用傳遞了(就是傳遞的真實內存地址),對於值類型來說就是值的內存地址,對於引用類型來說,就是這個引用的內存地址。這樣的操作,都會改變函數外變的量。

 

下面進行結果分析:

第一次執行(按地址傳參):

            int i = 100;
            args ar=new args();
            string str = "One";//特殊的引用類型
            ChangeValueyin(ref i);
            ChangeValueyin(ref ar);
            ChangeStingyin( ref str);
            Console.WriteLine(i);//200
            Console.WriteLine(ar.j);//600
            Console.WriteLine(str);//Two

其結果對比:

i=100-----執行函數後i=200

ar.j=5-----執行函數後ar.j=600

str="One"-----執行函數後str="Two"

無論是值類型,還是引用類型,按地址傳遞都將改變其原來值。

 

第二次執行(按值傳參):

            ChangeValuezhi(i);
            ChangeValuezhi(ar);
            ChangeStringzhi(str);
            Console.WriteLine(i);//100
            Console.WriteLine(ar.j);//600
            Console.WriteLine(str);//One

其結果對比:

i=100-----執行函數後i=100

 

ar.j=5-----執行函數後ar.j=600

 

str="One"-----執行函數後str="One"

 

可以看出,當按值傳參的時候,i與ar.j執行函數後結果是不一樣的。

i沒有被改變,因爲傳遞的是i=100這個值的一個拷貝,對它的任何操作不會對原來的i=100有任何改變。

 

args類中j的值被改變了,因爲args是引用類型,當按值(這個值就是args引用的一個拷貝)傳遞args時,

傳遞的是args引用的拷貝,引用拷貝和原來的引用都指向同一個對象,所以j被改變了。

 

再看str定義的是string類型,string也是引用類型,爲什麼沒有像args一樣?

string是特殊的引用類型,它具有恆定性,也就是說,一個字符串創建以後,不能再對它進行任何更改

對它更改都會重新創建一個新的字符串

比如:string str="avb"執行object.ReferenceEquals(str,str.ToUpper())將得到false

如果按一般引用類型,對原有引用上的修改不會引起重新創建一個新的對象。

如果對一個字符進行頻繁的操作,這時你應該考慮用StringBuilder,StringBuilder維護的是一個字符串數組

對它的操作,會體現到它本身,而不是去創建另一個字符串對象,這樣比對string的操作節省了內存空間

 

另外補充:

ref 參數傳入前必須被初始化,out不用,out需要在過程中對它初始化

可以通過ref和out來實現方法重載,但又不允許通過區分ref和out來實現方法重載

比如上面可以實現ChangeValueyin ref或者out的重載

ChangeValueyin(int iVlaue)
ChangeValueyin(ref int iVlaue)

這樣將不被允許

ChangeValueyin(out int iVlaue)
ChangeValueyin(ref int iVlaue)

 

 

僅代表個人觀點,如果認識有什麼不足還請指教!!!

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