• C#引用传递[转]


    学过C#的人都知道,通过或通过引用,值类型和引用类型都可以作为方法参数传递。在C#中,不管是值类型或者是引用类型,所有方法参数在默认情况下是通过值传递的。


    1)通过值传递值类型
    在通过值传递作为方法参数的变量时,传递给方法的是数据副本。在方法中对该数据的任何修改都不会对初始值有任何影响
    C#如下代码:

    [csharp] view plain copy
    1. using System;  
    2. class MyExecutableClass  
    3. {  
    4. static void Main(string[] args)  
    5. {  
    6. int value=50;  
    7. DoSometing(value);  
    8. Console.WriteLine(value);  
    9. }  
    10.   
    11. static void DoSomething(int parameter)  
    12. {  
    13. parameter=100;  
    14. }  
    15. }  
    程序的输出为50.也许你会感到奇怪,为什么不是100呢?因为变量value是通过值而不是引用传递的。我们不需要添加任何特殊的关键字,而是依赖于C#的默认行为,通过值传递值类型。
    2)通过引用传递值类型
    通过引用传递值类型,也就是说传递值(变量)的引用。如果传递引用的话,那么无论在程序的什么地方作改变的话(可能是在另一个方法、属性中,甚至是另一个对象中),都会改变使用改引用的值。对方法中任何参数的改变都将影响方法的返回值。
    在C#中,通过引用传递是通过ref关键字实现的,必须按如下所示将ref关键字添加到方法定义中:
    static void DoSomething(ref int parameter)
    传递参数时,必须使用ref关键字。
    DoSomething(ref value)
    下面的代码演示了如何对值类型使用ref关键字:
    [csharp] view plain copy
    1. using System;  
    2. class MyExecutableClass  
    3. {  
    4. static void Main(string[] args)  
    5. {  
    6. int value=50;  
    7. DoSomething(ref value);  
    8. Console.WriteLine(value);  
    9. }  
    10. static void DoSomething(ref int parameter)  
    11. {  
    12. parameter=100;  
    13. }  
    14. }  
    结果正如你所料,输出为100.

    3)通过值传递引用类型
    一般来说,通过值传递意味着传递存储在栈中的值。对于引用类型来说,存储在栈上的值表示对
    内存中对象实际位置的引用。因此,如果通过值传递引用类型,就意味着传递的是对象的引用(它的堆栈)
    .使用该引用作的改变最终会改变堆中的同一对象。
    通过值传递引用类型不像通过值传递值类型---它更像通过引用传递值类型。在如下代码中,
    我们将Person用作引用类型。

    [csharp] view plain copy
    1. using System;  
    2. class MyExecutableClass  
    3. {  
    4. static void Main(string[] args)  
    5. {  
    6. Person person=new Person(50);  
    7. DoSomething(person);  
    8. Console.WriteLine(person.Age);  
    9. }  
    10. static void DoSomething(Person somePerson)  
    11. {  
    12. somePerson.Age=100;   
    13. }  
    14. }  
    15. class Person  
    16. {  
    17. public int Age;  
    18. public Person(int Age);  
    19. {  
    20. this.Age=Age;  
    21. }  
    22. }   
    运行程序,可以发现输出值为100.

    如果对DoSometing方法作如下修改;

    [csharp] view plain copy
    1. static void DoSomething(Person somePerson)  
    2. {  
    3. somePeron=new Person(100);  
    4. }  

    重新运行程序,发现输出为50.这是因为我们并没有将引用传递给方法?
    答案是:不,我们确实发送了引用。引用类型有两个元素---引用和对象。现在,在
    调用DoSomething()方法时,我们创建了一个引用副本,它仍然指向同一对象,因此,对对象的改变会影响主程序。而对引用的改变则不会,在方法结束时,消失的只是引用的副本。
    1。在使用somePerson.Age属性改变年龄时,我们改变的是对象

    2。但接下来是创建一个新对象,改变引用来指向它---对引用的改变将会丢失。
    应该怎么做呢?方案就是通过引用传递引用类型,那样作的话,如果改变somePerson所存储的引用,那么另一个“父”引用会自动更新。听起来很混乱,下面再讨论。

    4) 通过引用传递引用类型
    我们知道,在通过值传递引用类型时,我们传递对内存中对象位置的引用。而通过引用传递引用类型时,我们将传递引用的引用。
    正如我们所看到的,通过值传递引用类型并不适合于所有情况---特别是需要改变引用以指向新对象时。
    下面例子就是说明通过引用传递就很有用。
    1. <pre name="code" class="csharp"></pre><pre name="code" class="csharp">using System;  
    2. class MyExecutableClass  
    3. {  
    4. static void Main(string[] args)  
    5. {  
    6. Person person=new Person(50);  
    7. DoSometing(ref person);  
    8. Console.WriteLine(person.Age);  
    9. }  
    10. static void DoSometing(ref Person somePerson)  
    11. {  
    12. somePerson=new Person(100);  
    13. }</pre><pre name="code" class="csharp">} </pre>  
    14. <pre></pre>  

    这次输出为100;person变量实际上对堆上Person对象的引用。在调用DoSomething()时,编译器创建了对Person引用的引用(而不是对Person对象的引用).在DoSometing()方法中,somePerson是Person引用的引用,而Person引用堆上的对象。然而,DoSomething()知道值是通过引用传递的,因此对somePerson的任何改变实际上是改变了person。结果就是somePerson的行为就好像它是person引用,而不是其副本。

    附测试代码,加深理解:


            static void CallDoType()
            {
                //传递值类型
                int value = 50;
                //DoValueTransferValueType(value);
                //DoReferenceTransferValueType(ref value);
                //Console.WriteLine(value);

                //传引用类型 传类
                Person person = new Person(50);
                //DoValueTransferReferenceType(person);
                DoReferenceTransferReferenceType(ref person);
                Console.WriteLine(person.Age);
            }

            /// <summary>
            /// 通过值传递值类型 在通过值传递作为方法参数的变量时,传递给方法的是数据副本。在方法中对该数据的任何修改都不会对初始值有任何影响。
            /// </summary>
            /// <param name="parameter"></param>
            static void DoValueTransferValueType(int parameter)
            {
                parameter = 100;
            }

            /// <summary>
            /// 通过引用传递值类型 在C#中,通过引用传递是通过ref关键字实现的
            /// </summary>
            /// <param name="parameter"></param>
            static void DoReferenceTransferValueType(ref int parameter)
            {
                parameter = 100;
            }

            /// <summary>
            /// 通过值传递引用类型 一般来说,通过值传递意味着传递存储在栈中的值。对于引用类型来说,存储在栈上的值表示对内存中对象实际位置的引用。
            /// </summary>
            /// <param name="parameter"></param>
            static void DoValueTransferReferenceType(Person somePerson)
            {
                //somePerson.Age = 100;   // 输出100

                //引用类型有两个元素---引用和对象。现在,在调用DoSomething()方法时,我们创建了一个引用副本,它仍然指向同一对象,因此,对对象的改变会影响主程序。
                //而对引用的改变则不会,在方法结束时,消失的只是引用的副本。
                somePerson = new Person(100);   //输出50:
                /*1。在使用somePerson.Age属性改变年龄时,我们改变的是对象。

    2。但接下来是创建一个新对象,改变引用来指向它---对引用的改变将会丢失。
    应该怎么做呢?方案就是通过引用传递引用类型,那样作的话,如果改变somePerson所存储的引用,那么另一个“父”引用会自动更新*/
            }
            /// <summary>
            /// 通过引用传递引用类型
            /// 在通过值传递引用类型时,我们传递对内存中对象位置的引用。而通过引用传递引用类型时,我们将传递引用的引用。
            /// </summary>
            /// <param name="parameter"></param>
            static void DoReferenceTransferReferenceType(ref Person somePerson)
            {
                somePerson = new Person(100);
            }

    class Person
    {
        public int Age;
        public Person(int Age)
        {
            this.Age = Age;
        }
    }

  • 相关阅读:
    Redis Info详解
    ABAP常用事务码
    ABAP区别CLEAR、REFRESH、FREE
    virtualbox安装增强功能时【未能加载虚拟光盘】
    https://www.safaribooksonline.com/home/
    图文教程教您蓝底照片更换成白底和红底的方法
    URAL1495. One-two, One-two 2(dp)
    URAL1513. Lemon Tale(dp)
    URAL1900 Brainwashing Device(dp)
    Codeforces Round #228 (Div. 1)B
  • 原文地址:https://www.cnblogs.com/jimcsharp/p/6560161.html
Copyright © 2020-2023  润新知