zoukankan      html  css  js  c++  java
  • 【原创】理解C#的引用类型的值传递

    C#中,数据传递的方式有两种:按值传递和按引用传递,且默认情况下都是按值传递。而CLR支持两种基本类型为:值类型和引用类型。

    1. 当传递的参数为值类型,且数据传递方式为按值传递时,传递的是数据的一个拷贝。

    2. 当数据传递方式为按引用传递时,必须以ref或者out关键字来修饰。由于这部分不是本文主题,不做详细介绍,想了解相关内容可参见【原创】C#中ref和out的异同

    3. 当引用类型参数按值传递时,传递的是引用类型地址的数据拷贝。

    下面通过例子来验证第3点中所说

    先看以下示例代码:

    class Program
    {
    public static void Main()
    {
    var abf
    = new ArgsByRef();
    var abf1
    = abf;
    AddRef(abf);
    Console.WriteLine(abf.i);
    ReplaceRef(abf1);
    Console.WriteLine(abf.i);
    Console.WriteLine(abf1.i);
    }

    private static void AddRef(ArgsByRef abf)
    {
    abf.i
    = 20;
    Console.WriteLine(abf.i);
    }

    private static void ReplaceRef(ArgsByRef abf)
    {
    if (abf == null) throw new ArgumentNullException("abf");
    var m
    = new ArgsByRef();
    abf
    = m;
    Console.WriteLine(abf.i);
    }
    }

    public class ArgsByRef
    {
    public int i = 10;
    }

    现在开始来详细分析以上代码:

    1. var abf = new ArgsByRef(); 语句创建一个ArgsByRef实例abf,假设abf实例指向的堆中地址为0x1323。如图:

    2. var abf1 = abf; 语句创建一个ArgsByRef实例abf1,并将abf1实例的引用地址指向abf实例的引用地址,即abf1实例同样指向地址0x1323。

    3.

    AddRef(abf);
    private static void AddRef(ArgsByRef abf)
    {
    abf.i
    = 20;
    Console.WriteLine(abf.i);
    }

    执行AddRef方法时,传递abf实例作为参数。由于传递的是对象的引用,所以在方法内对对象的修改会直接影响对象。如图:

    4. 当执行ReplaceRef方法时,传递abf1实例作为参数,创建ArgsByRef实例m,假设实例m指向的堆地址为0x1345。如图:

    5. 当执行abf=m时,其实是创建了一个abf1实例引用地址的拷贝,使当前abf1实例的引用地址为0x1345。这里重点在于引用地址的拷贝,我画的表示图如下(不知道对与不对,还望大哥们多指点一下):

    6. 退出ReplaceRef方法,回到主方法后,由于是引用类型的引用地址的值传递,所以并没有改变对象的引用地址。实例abf1的引用地址仍为0x1323。

    所以abf1.i仍为20

    最后:说了这么多,也不知道描述清楚没有,如果有错误,还希望各位看官能不吝指点。我认为重点理解引用地址的拷贝。希望对大家理解值类型和引用类型,以及按值传递和按引用传递有帮助。

  • 相关阅读:
    leetcode-剑指19-OK
    leetcode-剑指38-?
    leetcode-剑指36-OK
    leetcode-剑指41-OK
    leetcode-剑指20-OK
    leetcode-剑指16-OK
    nginx重写路由隐藏入口文件报错引发的思考
    Go之并发
    Go之接口
    Go实现学生管理系统
  • 原文地址:https://www.cnblogs.com/zwffff/p/1961585.html
Copyright © 2011-2022 走看看