• C#基础原理拾遗——引用类型的值传递和引用传递


    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。

          至此,我总结出:值传递是传递栈中的值;引用传递是传递栈地址。

          这一次我是蛮认真的写的这篇博客,希望人气能好一点,不吝留言赐教的话就感激不尽了。

  • 相关阅读:
    用Service充当Domain Object
    Scrum方法回顾
    为什么使用User Story Map
    前端状态管理之状态机
    项目进度管理注意事项
    单元测试遇到的最难的问题
    JS AMD模块的循环依赖
    jupyter notebook常用快捷键
    Jupyter-NoteBook-你应该知道的N个小技巧
    Python之配置日志的几种方式(logging模块)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3173840.html
Copyright © 2020-2023  润新知