C#基礎原理拾遺——引用類型的值傳遞和引用傳遞


      以前寫博客不深動,只搭個架子,像做筆記,沒有自己的思考,也沒什么人來看。這個毛病得改,就從這一篇開始…

      最近准備面試,深感基礎之重要,奈何我不是計算機科班出身,基礎方面有些捉襟見肘。短期怎么補?做面實題唄。遇到哪兒沒理解透,自己查資料,印象深刻。這個問題就是這么來的。原題很簡單:“對於方法,參數傳遞分為值傳遞和____兩種。”這還不簡單,但我得拓展啊,得思考啊…

      以下1、2是我的意淫,但記錄自己的一些錯誤想法並思考改正還是有益處的,希望不會對大家有誤導。覺得麻煩的話可以直接看3。

1、什么是值傳遞和引用傳遞?

      我一開始的理解是,值類型根本沒有引用啊,它能有引用傳遞?它的值傳遞和引用傳遞應該是一樣的。至於引用類型,它的值傳遞應該是一個深拷貝,引用傳遞應該是一個淺拷貝。對於這一類比,最初還頗感得意。但查資料才知道,What a stupid idea!沒辦法,非科班出身,知識不成體系,有盲點,但我知道這不是借口,這不在大補嘛,補得跟小雞子似的。

      看了http://www.cnblogs.com/whc-blog/archive/2011/07/20/2111803.html這篇,感性的知道了什么是值傳遞和引用傳遞。其實也不是壓根不知道,長時間不用忘了,然后就出現了上面離奇的想法。

      其實在整個思考完了以后我給值傳遞和引用傳遞下了個定義,在這里先搬出來:(歡迎大家批評指正)

值傳遞是傳遞棧中的值;引用傳遞是傳遞棧地址。

2、引用類型的值傳遞和引用傳遞可以類比成深拷貝和淺拷貝嗎?

     到此對於這個問題還是有疑問的,就寫了個小Demo

class Program
    {
        static void Main(string[] args)
        {
            Student xiaohong = new Student("小紅", 12);
            BanZheng(ref xiaohong);
            //BanJiaZheng(xiaohong);
            Console.WriteLine(xiaohong.Name + "  " + xiaohong.Age);
            Console.ReadKey();
        }

       //辦證
        static void BanZheng(ref Student student)
        {
            student.Name = "紅姐";
            student.Age = 18;  
        }
       //辦假證
        static void BanJiaZheng(Student student)
        {
            student.Name = "紅姐";
            student.Age = 18;       
        }
    }

    class Student
    {
        public Student(string name, int age)
        {
            Name = name;
            Age = age;
        }
        public string Name { get; set; }
        public int Age { get; set; }
    }

      解釋一下:小紅今年12,但她要工作,可能家庭困難吧。1、如果她有關系(有關系還家庭困難?解釋不了),找到BanZheng方法,給她身份證改成“紅姐”18,拿去Main方法輸出驗證,果然輸出“紅姐”18。呵呵。但按我理解,ref如果是淺拷貝的話,Age作為一個值類型屬性應該是重新烤了一份,其值不應該回傳給xiaohong啊,應該輸出“紅姐”12。看來有關系就是牛逼啊。2、如果她沒關系,找了個辦假證的BanJiaZheng,一驗證還是“紅姐”18,如果按我理解,值傳遞是深拷貝的話,student參數應該和xiaohong是兩個完全不同的對象,應該輸出“小紅”12,看來這個認證機構(我的理解)有水。於是我再查資料…

3、引用類型的值傳遞和引用傳遞揭秘

     功夫不負有心人,找到這么一篇好文http://www.cnblogs.com/duanwg/archive/2006/07/21/456247.html,其實看了它就能理解了,但我還是根據上面的Demo做些改進,加深理解。

class Program
    {
        static void Main(string[] args)
        {
            Student xiaohong = new Student("小紅", 12);
            BanZheng(ref xiaohong);
            //BanJiaZheng(xiaohong);
            Console.WriteLine(xiaohong.Name + "  " + xiaohong.Age);
            Console.ReadKey();
        }

        static void BanZheng(ref Student student)
        {
            //student.Name = "紅姐";
            //student.Age = 18;

            student = new Student("紅姐", 18);       
        }

        static void BanJiaZheng(Student student)
        {
            //student.Name = "紅姐";
            //student.Age = 18;

            student = new Student("紅姐", 18);           
        }
    }

    class Student
    {
        public Student(string name, int age)
        {
            Name = name;
            Age = age;
        }
        public string Name { get; set; }
        public int Age { get; set; }
    }

      這一次辦證方法改了,在方法體中student = new Student(…)。再到Main方法中驗證一下,如果調用BanZheng方法,輸出“紅姐”18,如果調用BanJiaZheng方法,輸出“小紅”12。看來有關系到什么時候都很牛逼啊。

      畫兩個圖理解一下:

(1)如果是BanJiaZheng,即值傳遞的話:

捕獲

變量xiaohong和student的棧中有相同的堆地址,都指向10000,即“小紅”12,而在BanJiaZheng方法中student = new Student(…),開辟了10010堆,student的棧中的堆地址改為10010,而xiaohong的棧中堆地址還是10000。所以方法調用后xiaohong指向的對象沒變,依然是“小紅”12。

(2)如果是BanZheng,即引用傳遞的話:

捕獲1

變量xiaohong和student指向同一棧地址,在student = new Student(…)后,該棧001指向新的堆地址10010,而xiaohong也指向001棧。所以方法調用后xiaohong指向的對象變成了“紅姐”18。

      至此,我總結出:值傳遞是傳遞棧中的值;引用傳遞是傳遞棧地址。

      這一次我是蠻認真的寫的這篇博客,希望人氣能好一點,不吝留言賜教的話就感激不盡了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM