zoukankan      html  css  js  c++  java
  • 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;
        }
    }

  • 相关阅读:
    web前端的发展态势
    AngularJs 简单入门
    css代码优化篇
    git提交报错:Please make sure you have the correct access rights and the repository exists.
    Activiti工作流框架学习
    遍历map集合的4种方法
    js设置日期、月份增加减少
    Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    webservice_rest接口_学习笔记
    相互匹配两个list集合+动态匹配${}参数
  • 原文地址:https://www.cnblogs.com/jimcsharp/p/6560161.html
Copyright © 2011-2022 走看看