zoukankan      html  css  js  c++  java
  • C#值类型与引用类型在使用上的区别

    • 值类型与引用类型

    为了探明两者区别,直接看代码:

        public class Object_1
        {
            private int m_Age;
    
            public int Age
            {
                get { return m_Age; }
                set { m_Age = value; }
            }
    
            private string m_Namr;
    
            public string Name
            {
                get { return m_Namr; }
                set { m_Namr = value; }
            }
        }
        public struct Struct_1
        {
            private int m_Age;
    
            public int Age
            {
                get { return m_Age; }
                set { m_Age = value; }
            }
    
            private string m_Namr;
    
            public string Name
            {
                get { return m_Namr; }
                set { m_Namr = value; }
            }
        }

    在上面我们定义了一个类(Object_1)和一个结构体(Struct_1)。我们都知道类是引用类型,而结构体是值类型,所以接下来进行对比,我们让两者在Change()方法中改变值:

           private void Form1_Load(object sender, EventArgs e)
            {
                Object_1 obj = new Object_1();
                obj.Age = 1;
                obj.Name = "Mike";
                Struct_1 stru = new Struct_1();
                stru.Age = 2;
                stru.Name = "Tim";
                Change(obj,stru);
                MessageBox.Show("obj.Age:" + obj.Age + "
    obj.Name:" + obj.Name + "
    stru.Age:" + stru.Age + "
    stru.Name:" + stru.Name);
            }
    
            public void Change(Object_1 obj_1, Struct_1 stru_1)
            {
                obj_1.Age += 10;
                obj_1.Name += "_Obj";
                stru_1.Age += 10;
                stru_1.Name += "_Stru";
            }

    得到结果:


    可以发现,obj.Age与obj.Name的值发生了改变,但是stru.Age与stru.Name的值依然与之前一样。

    在Change()方法内部obj_1与stru_1的值都被改变,但是为什么在执行完Change()之后却出现差异。那可以设想为我们所改变的stru_1实际上不是真正的源参数。查询资料后得知:

    那是因为在Change()方法内部obj_1被视为与传进obj参数是一个对象,而stru_1只是将参数stru的值Copy了一份。所以我们在内部修改stru_1的值只是修改了这个“替身”的值,本体的值并未修改


    所以也可以得出结论:

    值类型在方法体内作为参数被时,只是将值Copy一份使用,因而对其所做操作都无法对源参数产生影响。

    引用类型在方法体内被作为参数时,内部对象与参数对象一致,对其所做的操作会影响到源参数。



    PS:int型,long型,char型等数据类型都是struct,所以符合我们上面的结论。


    • ref与out

    继续深入:

    有时,我们也希望能将值类型像引用类型一样使用,比如在方法内修改值类型也影响源参数。

    C#内相应提供了两个关键词:ref,out  (两者区别参考这里

    当使用这两个关键词之后,我们看看有什么变化,修改上面的代码如下:

            private void Form1_Load(object sender, EventArgs e)
            {
                Object_1 obj = new Object_1();
                obj.Age = 1;
                obj.Name = "Mike";
                Struct_1 stru = new Struct_1();
                stru.Age = 2;
                stru.Name = "Tim";
                Change(obj,ref stru);//此处被修改
                MessageBox.Show("obj.Age:" + obj.Age + "
    obj.Name:" + obj.Name + "
    stru.Age:" + stru.Age + "
    stru.Name:" + stru.Name);
            }
    
            public void Change(Object_1 obj_1, ref Struct_1 stru_1)//此处被修改
            {
                obj_1.Age += 10;
                obj_1.Name += "_Obj";
                stru_1.Age += 10;
                stru_1.Name += "_Stru";
            }
    结果如下:



    stru.Age与stru.Name的值发生了变化。这也达到了我们需求,值类型也可以像引用类型一样使用。

    但是原因是什么?

    原因在于方法体在执行时,编译器根据ref关键词将值类型与参数对象“等同”了起来,而不是将值Copy一份。

    这所有的一切究其原因,是在方法体内有种机制,这种机制将参数加上"签名"(可以理解为与身份证号类似的唯一标识),当是引用类型时,签名与外侧参数相同,值类型时则使用不同的“签名”。除非使用了ref或out关键词,值类型的“签名”才与源参数一致。


    • new对象

    刚刚我们说的都是改变值,若是将new对象呢?继续修改上面Change()方法代码如下:

            public void Change(Object_1 obj_1, ref Struct_1 stru_1)
            {
                obj_1 = new Object_1();//此处被修改
                obj_1.Age += 10;
                obj_1.Name += "_Obj";
                stru_1.Age += 10;
                stru_1.Name += "_Stru";
            }
    结果如下:



    由于在Change()内obj_1对象被new了,所以新对象的“签名”与源参数的“签名”已经不同,所以方法内部值的改变不影响原来的对象。如果要使new对象影响源参数,依然可以使用ref

           public void Change(ref Object_1 obj_1, ref Struct_1 stru_1)


    • string类型

    有人说string类型是特殊的引用类型,因为它与值类型一样在方法内部改变后无法影响原参数,为了验证,继续修改代码如下:

         private void Form1_Load(object sender, EventArgs e)
            {
                Object_1 obj = new Object_1();
                obj.Age = 1;
                obj.Name = "Mike";
                Struct_1 stru = new Struct_1();
                stru.Age = 2;
                stru.Name = "Tim";
                string str = "A";//此处被修改
                Change(ref obj, ref stru, str);
                MessageBox.Show("obj.Age:" + obj.Age + "
    obj.Name:" + obj.Name + "
    stru.Age:" + stru.Age + "
    stru.Name:" + stru.Name + "
    str:" + str);//此处被修改
             }
    
            public void Change(ref Object_1 obj_1, ref Struct_1 stru_1, string str)//此处被修改
            {
                obj_1 = new Object_1();
                obj_1.Age += 10;
                obj_1.Name += "_Obj";
                stru_1.Age += 10;
                stru_1.Name += "_Stru";
                str = "B";//此处被修改
            }
    

    结果如下:



    表面上str的值没有改变,依然是“A”。但是不要只看表面,之所以依然显示为“A”,,是因为在这里string=运算符实际上等同于str=new String(new char[]{'B'});也就是new了一个新对象, 那str的“签名”也自然就与源参数不同,也就不会影响源参数(与 obj_1 = new Object_1()是同样的道理)。


    作者:Mr.Jimmy
    出处:https://www.cnblogs.com/JHelius
    联系:yanyangzhihuo@foxmail.com
    如有疑问欢迎讨论,转载请注明出处

  • 相关阅读:
    C# 应用
    WPF 应用
    WPF 应用
    WPF 应用
    WPF 基础
    WPF 基础
    WPF 应用
    WPF 应用
    下厨房
    买苹果
  • 原文地址:https://www.cnblogs.com/JHelius/p/14318923.html
Copyright © 2011-2022 走看看