C#-值传递与引用传递的区别,使用ref与out的区别 086

值类型与引用类型

简单来说就是将值类型变量或引用类型变量作为参数传入方法操作后原值的变化

简单回顾,之前细说过值类型与引用类型的区别在内存中的变化,因此不再赘述

1)内存中的区别:值类型主要存储在中;引用类型存储在中栈,堆中(主要是堆)

2)继承中的区别:值类型继承自System.ValueType(System.ValueType又继承自System.Object) 引用类型继承自System.Object;因此C#中Object类可以称之为”祖宗类”

值类型主要有:byte,int,short,float,double,long,decimal,char,bool,struct,enum等

引用类型主要有:object,string,Array,class,interface等

C#-值传递与引用传递的区别,使用ref与out的区别 086

值类型与引用类型各自的继承关系

值类型变量赋值会拷贝一个副本 引用类型变量的赋值只复制对对象的引用

static void Main(string[] args)
{
    //值类型
    int n = 6;
    int m = n;
    m = m + 2;
    Console.WriteLine("n = {0}  m = {1}", n, m);
    Console.WriteLine("");
  //修改m的值不会影响n的值
  //验证:拷贝一个副本 
    //引用类型
    int[] ns1 = new int[1] { 1 };
    Console.WriteLine("ns1[0] = {0}", ns1[0]);
    int[] ns2 = ns1;
    Console.WriteLine("ns2[0] = {0}",ns2[0]);
    ns1[0] = 3;
    Console.WriteLine("ns1[0] = {0}",ns1[0]);
   //修改ns2[0]的值会影响ns1[0]的值
  //验证:复制对对象的引用
  //看不懂的单击上面连接或查找039文章
  //详细说明了内存中变量指针的指向,不再赘述
    Console.ReadKey();  
}

值传递

将值类型变量或数据传入方法操作后查看原值(主要是理解值类型传递副本)

C#-值传递与引用传递的区别,使用ref与out的区别 086

值传递

 static void Main(string[] args)
 {
     int n = 6;
     M1(n);//在方法内部 X=9
     //方法未返回x操作后的值
    //因此n 还是原值 6
     Console.WriteLine(n);//6
     Console.WriteLine("");
    //在方法内部操作后返回
   //最关键的是n又接收了操作后的值
   //因此 n =9
     n = M2(n);
     Console.WriteLine(n);//9
     //如果 m 没有进行接收
      int m = 6;
      M2(m);
     //M2()虽然有返回值,但是没有接收
     //因此 M2()中 y =9
     //m 还是原值 6
      Console.WriteLine(m);//6
			//m 没有接收M2()的返回值
      //无论在方法内对m做任何操作,外部的m值不变
     Console.ReadKey();
 }
//静态方法
static void M1(int x)
 {
   //无论怎么加减乘除,都不影响外部 n 的值
     x += 3;
 }
 static int M2(int y)
 {
   //操作后返回
   //如果外部没有接收 m还是原值
   //如果外部 m 接收了方法的返回值 
   //m 就是9 相当于 6+3 
     return y += 3;
 }

引用传递

将引用类型的变量或数据传入方法(主要是理解引用类型传递的是对象的地址)

 static void Main(string[] args)
 {
  Person p1 = new Person();
  p1.Name = "张三";
  p1.Age = 18;
  M3(p1);//结果 李四 180
  Console.WriteLine(p1.Name + "  " + p1.Age);    
  Console.ReadKey();
 }
static void M3(Person p3)
{
    p3.Name = "李四";
    p3.Age = 180;
}

C#-值传递与引用传递的区别,使用ref与out的区别 086

把p1对象在栈中的地址赋给p3(p3 类似是 p1 的快捷方式)

 static void Main(string[] args)
 {
  Person p1 = new Person();
  p1.Name = "张三";
  p1.Age = 18;
  M3(p1);//结果 李四 180
  Console.WriteLine(p1.Name + "  " + p1.Age);    
  Console.ReadKey();
 }
static void M3(Person p3)
{
    p3.Name = "李四";
    p3.Age = 180;
}

C#-值传递与引用传递的区别,使用ref与out的区别 086

将p2对象的堆地址赋给p5即p5对象也指向p2对象

 static void Main(string[] args)
 {
   Person p3 = new Person();
   p3.Name = "王五";
   p3.Age = 19;
   M6(p3);//王五 19
   Console.WriteLine(p3.Name + "  " + p3.Age);
   Console.ReadKey();
 }
static void M6(Person px)
{
    Person p6 = new Person();
    px = p6;
    px.Name = "张三三";
    px.Age = 190;
}

C#-值传递与引用传递的区别,使用ref与out的区别 086

px指向p6对象 因此修改的不再是 p3的属性值

px与p6指向堆地址 0x002,最后只有p3指向堆地址 0x001

//对照前三个示例,自己理清 M7()方法的结果
static void Main(string[] args)
{
   Person p4 = new Person();
   p4.Name = "王五";
   p4.Age = 19;
   M7(p4);//张三  20
   Console.WriteLine(p4.Name + "  " + p4.Age);  
   Console.ReadKey();
}
 static void M7(Person p4x)
 {
     p4x.Name = "张三";
     p4x.Age = 20;
     Person p7 = new Person();
     p4x = p7;
     p4x.Name = "王五";
     p4x.Age = 190;
 }

使用ref/out进行传值

ref和out都是按地址传递,使用后都将改变原参数的值(值类型,传递的是栈本身的地址;引用类型,传递的是引用地址所在栈的地址)

out修饰的参数在方法外部既可以赋值也可以不赋值;在方法该参数必须赋值

ref修饰的参数与其正好相反

//对照前三个示例,自己理清 M7()方法的结果
static void Main(string[] args)
{
     //使用ref传值
     //传入值类型
     int n = 6;
     M8(ref n);//9
     Console.WriteLine(n);
     Console.WriteLine("");
     //传入引用类型
     int[] ns = new int[] { 1 };
     M9(ref ns);//8
     Console.WriteLine(ns[0]);
     //=========================
     //使用out进行传值
     //传入值类型
     int m = 8;
     M10(out m);//2
     Console.WriteLine(m);
     Console.WriteLine("");
     //传入引用类型
     int[] ms = new int[1];
     ms[0] = 1;
     M11(out ms);//5
     Console.WriteLine(ms[0]);     
     Console.ReadKey();
}
static void M8(ref int nx)
{
    nx = nx + 3;
}
static void M9(ref int[] nsx)
{
    nsx = new int[] { 8 };
}
static void M10(out int m)
{
    m = 2;
}
static void M11(out int[] msx)
{
    msx = new int[1] { 5 };
}

C#-值传递与引用传递的区别,使用ref与out的区别 086

使用ref/out 传递值类型或引用类型

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 共4条

请登录后发表评论