.net c# 传参 引用 ref 传入值类型

作者:袖梨 2022-06-25


下面贴代码:

 代码如下 复制代码
using System;
 using System.Collections.Generic;
 using System.Text;
 
 namespace ClassObjectAndStringDiffDemo
 {
     class Program
     {
         static void Main(string[] args)
         {
             //作为传入参数的变量或对象,以下称呼为‘原变量’或‘原对象’
             string str = "123";//"123"是一个对象,相当于String str = new String("123");赋值的过程其实内存地址指向也已改变
 
             Console.WriteLine("/********************************/");
             Console.WriteLine("1:传参:均传递的是传递类型的对象值的Copy,");
             Console.WriteLine("  不同的是值类型的Copy的为值,引用类型的Copy的为对象的引用地址");
             Console.WriteLine("2:String定义类型为Class ,是引用类型,其他的基本数值类型,为struct,所以为值类型,");
             Console.WriteLine("  所以string的赋值过程为对象的内存交换,");
             Console.WriteLine("  string str = "123";//"123"是一个对象,相当于String str = new String("123");");
             Console.WriteLine("3:不管传参 的类型是引用类型还是值类型,均可称为按值传递,");
             Console.WriteLine("  因为,传递的是Copy,值类型为值的Copy,引用类型为引用地址的Copy");
             Console.WriteLine("4:在传参函数的内部,操作的为Copy,值类型因为操作的为传入变量(值)的副本(新的内存地址),");
             Console.WriteLine("  所以改变的是副本(新的内存地址),与原变量无关,操作的不是指向同一块的内存;");
             Console.WriteLine("  引用类型因为传入的为变量(对象)的地址值的副本,虽然为Copy副本,但是仍然指向原变量的内存地址,");
             Console.WriteLine("  所以副本和原变量指向为同一块内存地址,副本操作的即为原变量的内存地址的内容。");
             Console.WriteLine("5:string和自定义的类的对象同作为传入参数,但操作结果不同的原因是:string由于其定义时的某种特殊性,");
             Console.WriteLine("  即声明初始化与常规类不同,不需要构造函数去构造,所以在表现上的不同,隐藏了它的实质是与同为引用");
             Console.WriteLine("  类型的常规类的相同的特性,string的赋值过程,即是把一个string对象的内存地址给予了传入的copy副本");
             Console.WriteLine("  即相同于PerSon类的对象实例,副本ps1,新对象ps2,ps1=ps2,这样之后操作ps1对象字段,其实操作的ps1也就不是原来的副本,");
             Console.WriteLine("  也就不是传入原对象的副本内存地址了,而是新的ps2的内存地址指向,这样就不能起作用了");
             Console.WriteLine("/********************************/");
 
             Console.WriteLine("Str初始化值");
             Console.WriteLine("Str:{0}",str);
 
             ChangeString(str);
             Console.WriteLine("Str做为不带修饰参数传递,为按地址(引用)传递");
             Console.WriteLine("Str:{0}", str);
 
             ChangeString(ref str);
             Console.WriteLine("Str带ref修饰传递,为按地址(引用)传递");
             Console.WriteLine("Str:{0}",str);           
 
             PerSon ps = new PerSon("111");
 
             Console.WriteLine("Person初始化name值");
             Console.WriteLine("Person.name:{0}",ps.name);
 
             ChangePerSonNew(ps);
             Console.WriteLine("Person对象做为不带修饰参数传递,为按地址(引用)传递,改值方式不同下");
             Console.WriteLine("Person.name:{0}", ps.name);
 
             ChangePerSonNew(ref ps);
             Console.WriteLine("Person对象做为不带修饰参数传递,为按地址(引用)传递,改值方式不同下");
             Console.WriteLine("Person.name:{0}", ps.name);
 
             ChangePerSonNew2(ref ps);
             Console.WriteLine("Person对象做为不带修饰参数传递,为按地址(引用)传递,改值方式不同下");
             Console.WriteLine("Person.name:{0}", ps.name);
 
             ChangePerSon(ps);
             Console.WriteLine("Person对象做为不带修饰参数传递,为按地址(引用)传递,改值方式不同上");
             Console.WriteLine("Person.name:{0}",ps.name);       
 
 
             int k = 1;
 
             Console.WriteLine("k初始化值");
             Console.WriteLine("k:{0}", k);
 
             ChangeVal(k);
             Console.WriteLine("k不带修饰参数传递,按值传递");
             Console.WriteLine("k:{0}",k);
 
             ChangeVal(ref k);
             Console.WriteLine("k带ref修饰参数传递,按引用传递");
             Console.WriteLine("k:{0}", k);
 
             Console.ReadLine();
         }
         ///
 ///
 ///

 /// 引用类型,ref作用相当于指针,这样传入的为原变量的地址,原变量必须先初始化
         static void ChangeString(ref string s)
         {
             //ref 起的作用,个人根据结果猜测,应该是保持s副本的内存地址引用在赋值过程不改变,只改变值
             s = "465";//s此时指向的仍为原变量的内存地址,但值改变,副本的地址指向为原变量的内存,而值改变,那么就改变的原变量的指向内存的内容
 
 //此情况相当于下面ChangePerSon(PerSon p)
         }
 
         ///
 ///
 ///

 /// 引用类型,此处传入的也为原变量的内存地址
         static void ChangeString(string s)
         {
             s = "456";//此处s副本传入时指向的为原变量的内存地址,此时赋值后,指向的为‘456’的内存地址,副本的内存指向变了,不影响原变量的内存内容
 
 //此情况相当于下面ChangePerSonNew(PerSon pson)
 
 //此就相当于string赋值时,隐藏看不见的代码
 //string str = new string("456");
 //假设string类有一个字段,'456'就相当于相当于string类的那个字段的值
 //s=str;s对象指向str对象。只是副本的更改,不涉及原对象的更改
         }
         //由于string类型比较特殊,看下面的值类型比较容易看出区别
 
         static void ChangeVal(int i)
         {
             i = 2;//此处i传入的为原变量的值的副本(新的内存地址,保存的原变量的值),所以改变副本i的值,不影响原变量内存的内容
 //所以结果无变化
         }
 
         static void ChangeVal(ref int i)
         {
             i = 3;//此处传入的为原变量的内存地址的副本(新的内存地址,保存的原变量的内存地址,即新的内存地址指向原变量的内存地址)
 //此时修改值,即修改的为的原变量的内存中保存的内容的值,所以会结果会有变化
         }
 
 
         ///
 ///
 ///

 /// 引用类型,传入原对象的内存地址的副本
         static void ChangePerSon(PerSon p)
         {
             p.name = "000";//name字段的内存指向变为‘000’的内存指向,但p的内存指向未变(原对象的地址),所以,p.name 指向的为‘000’的内存地址
 //所以表现的出来的结果是值变了,其实name 指向的内存已不是原有的那块内存
         }
         ///
 ///
 ///

 /// 引用类型,传入原对象的内存地址的副本
         static void ChangePerSonNew(PerSon pson)
         {
             PerSon pso = new PerSon();
             pso.name = "222";
             pson = pso;//pson副本的内存指向已改变为pso的内存地址,所以不影响原变量的内存中的内容
         }
 
         ///
 ///
 ///

 /// 引用类型,传入原对象的内存地址的副本
         static void ChangePerSonNew(ref PerSon pson)
         {
             PerSon pso = new PerSon();
             pso.name = "333";
             pson = pso;//ref 有保持内存地址不改变,只改变值的作用,对象包括字段
         }
 
         ///
 ///
 ///

 /// 引用类型,传入原对象的内存地址的副本
         static void ChangePerSonNew2(ref PerSon pson)
         {
             PerSon pso = new PerSon();
             pso.name = "444";
             pson.name = pso.name;//
             pson = pso;//ref 有保持内存地址不改变,只改变值的作用
         }
 
         sealed class PerSon
         {
             public string name;
             public PerSon(string n)
             {
                 this.name = n;
             }
             public PerSon()
             { }
         }
     }
 }


大家看完后给点意见,帮我修正下,当然如果有更通俗易懂,而且专业的说法,请大家踊跃分享哈,比较本文中个人

相关文章

精彩推荐