• C#值传递与引用传递的区别和用法


    1 类类型的数据传递

    C#和C++ 一样,有值传递和引用传递。例如下面的代码

    Person p1 = new Person();
    p1.Name = “张三”;

    Person p2 = p1;
    p2.Name = “李四”;

    Console.WriteLine(p1.Name);
    把对象p1赋值给p2, 此时p2修改Name属性,那么p1的Name属性也被修改了,类是 引用类型,一个对象的修改可能会涉及到其它对象的修改。但是对于string类型又不同,string具有不可变性,例如下面的代码

    //字符串的不可变性
    string str1 = “abc”;
    string str2 = str1;
    str2 = “dfg”;

    Console.WriteLine(“str1 = {0}”, str1);
    Console.WriteLine(“str2 = {0}”, str2);
    str1赋值给str2,修改str2的值,并不会 修改str1的值,这是string和其它类的区别,string赋值时会重新在堆上分配空间,之前的值依然存在。

    2 函数引用传参

    (1)基本数据类型

    public static void TestNum(ref int num) //相当于C++的引用传参
    {
    num += 10;
    }
    如果在函数参数的前面加了ref关键字,那么此时就和C++的引用传参是一样的,区别是C#在调用时, 实参前面也要加 ref修饰,不然会有语法错误。

    (2)类类型做形参

    public static void TestClass(Person p) //相当于C++的引用传参
    {
    p.Name = “赵六”;
    }
    此时传入对象,会修改对象的属性。

    3 返回ref类型的数组项

    例如下面的代码

    using System;

    namespace ref返回
    {
    class Program
    {
    public static ref int Test(int[] array)
    {
    return ref array[0];
    }

        static void Main(string[] args)
        {
            int[] array = { 5, 80 };
            ref int tmp = ref Test(array);
    
            Console.WriteLine("{0}, {1}", array[0], array[1]);
    
            tmp = 0;  //修改这个引用后,数组对应的元素值也被修改了
    
            Console.WriteLine("{0}, {1}", array[0], array[1]);
    
            Console.ReadKey();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    }
    函数Test返回的是ref类型的数组项,当调用Test函数后,如果外部修改返回值,对应的数组项也会被修改。
    对于值类型它在进行值得传递的时候传递都是它的数值,但是引用类型传递的都是传递引用,对于常见的引用类型,比如:

    xxx a=new xxx();

    当我们将a赋值到另一个xxx的对象(比如对象b),那么我们在利用对象b去操纵与利用a去操纵是一样的,因为它们指向的是同一块堆空间。

    引用类型:自定义类,数组,字符串,接口,集合

    值类型:int,double,float,char,bool,decimal,enum,struct

    值类型的值传递
    值类型存储的地方全部都在栈上。

    比如int a=10;

    此时我们输入这样的语句int b=a,那么会在栈上开辟一块空间去存储a的值,然后b就是指向该栈空间。所以说值类型是值传递,因为引用类型的传递时将栈上的指针进行传递,所以传递的仅仅只是指向堆空间的指针,所以时引用传递

    String特殊的引用传递
    因为String字符串有着不变性,如果我们去修改一个字符串,它的本质时开辟其他的堆空间,然后将之前的引用切断然后指向新开辟的堆空间,这就使得频繁修改字符串会导致空间的浪费。我们来看下面的例子:

    String a=”aaa“

    String b=a

    虽然String是引用类型,但是因为修改字符串的本质都是新开辟堆空间,然后修改引用,那么上面的语句执行的本质是在堆上开辟一个新空间,然后将b指向新开辟的空间,里面的值是“aaa”。

    ref和out
    因为值类型在作为参数传入的时候,传递的是一个新的栈空间,那么传入后,无论在方法的内部如何修改传入的参数,都无法改变外部的值类型变量,所以我们可以使用ref和out参数去修饰,使得传入的参数不是就的栈空间,而是值对象指向的那块栈空间,这样在方法内部修改,操作后就可以影响外部参数。

    out强调传入的是一个没有初始化的值类型。

    而ref强调传入的是一个初始化后的值类型。

  • 相关阅读:
    聊聊 RocketMQ 名字服务
    节点CODE相同会导致数据重复
    在Pi和Jetson nano上运行深度网络,程序被Killed
    改变自己 只需要两年
    高能预警!第十七届 D2 第一波话题新鲜出炉 ~
    网络安全(黑客)—0基础学习手册
    Red Giant Trapcode Suite 2024.0.1
    代码随想录算法训练营Day49|贪心算法8
    Java(SpringBoot)实现定时创建分表、查询分表数据(日志表、浏览记录表等实现)
    Java可重复注解接口(Repeatable Annotation Interfaces)
  • 原文地址:https://blog.csdn.net/weixin_41883890/article/details/127330685