当前位置:编程学习 > C#/ASP.NET >>

c#引用传递和值传递

我们知道,c#的数据类型分为值类型和引用类型。值类型包括基本类型(数值类型,bool类型等)、结构和枚举,引用类型包括类、委托、数组等。在使用方法传递变量时,就需要了解值类型和引用类型作为参数传递的机制了。

    先看下面一段代码:

   

namespace ConsoleApplication1 

    class Program 
    { 
        static void Main(string[] args) 
        { 
            int aNumber = 10; 
            A a = new A(); 
            a.Name = "aaaaaaaa"; 
            Console.WriteLine(aNumber); 
            Console.WriteLine(a.Name); 
            ToDouble(aNumber); 
            ToDouble(a); 
            Console.WriteLine(aNumber); 
            Console.WriteLine(a.Name); 
            Console.ReadKey(); 
        } 
        static void ToDouble(int number) 
        { 
            number *= 2; 
        } 
        static void ToDouble(A a) 
        { 
            a.Name += "ssssssss"; 
        } 
    } 
    class A 
    { 
        private string name; 
        public string Name 
        { 
            get { return name; } 
            set { name = value; } 
        } 
    } 

 

    输出结果为:

    10

    10

    10

    1010

    通过结果发现,值类型aNumber在经过函数处理后,再次输出时值并没有发生变化,而引用类型class A的属性发生了变化,为什么会发生这种情况?

    数据类型在内存中的保存时,值类型保存在堆栈中,引用类型将它的值保存在托管堆中,在堆栈中保存的是对堆上地址的引用,在方法中传递参数时,所有类型都是传递堆栈中的位置,具体过程为先在堆栈上复制一个传递的对象,然后将该对象传给参数,所以显而易见,数值类型保存在堆栈中,作为参数传递时直接复制了数值的一个副本给方法,方法对该副本所做的任何操作都不会影响到该数值的原值,但是引用类型复制的是堆栈上对堆的引用,该引用指向的仍然是堆上的引用类型,所以对应用类型所做的操作都会引起其本身的改变。

    下面我们再看一段代码:

   

namespace ConsoleApplication1 

    class Program 
    { 
        static void Main(string[] args) 
        { 
            string aStr="10"; 
            Console.WriteLine(aStr); 
            ToDouble(aStr); 
            Console.WriteLine(aStr); 
            Console.ReadKey(); 
        } 
        static void ToDouble(string aStr) 
        { 
            aStr+=aStr; 
        } 
    } 

 

    输出结果为:

    10

    10

    string类型是引用类型,所以在方法中传递的仍然是堆栈中对string变量引用的副本,但是为什么上面的代码并没有改变string变量的值呢?这里我们就需要知道,在c#中,string是一个比较特殊的类型,微软并不提倡我们些如下的代码:

   

namespace ConsoleApplication1 

    class Program 
    { 
        static void Main(string[] args) 
        { 
          string aStr="aaaaa"; 
          string aOtherStr="bbbbb"; 
          string theyConcat=aStr+aotherStr; 
        } 
    } 

 

    上面的代码首先声明了一个变量aStr,然后将其与另一个字符串连接,在具体实现过程中,系统先在托管对中保存了aaaaa值,在进行连接运算时,先将aaaaa的值复制一份,然后在后面连接bbbbb,最后将得到的新值的地址赋给aStr,所以此时aaaaa并没有在内存中删除,直到垃圾回收器将其回收。比较好的做法是在需要进行连接字符串操作时,使用StringBulider类进行操作,它会直接在对象后面进行连接操作,而不会先将值复制一遍。

    回到上面的方法来,当String类型作为参数传递时,系统会先在托管堆中将值复制一遍,堆栈上得到的地址指向这个新值,所以方法对string类型的操作并不影响到它的原有值。

    这里我们必然会想到,如果我需要使用一个方法改变值类型的值咋办呢?比如说,当我们需要一个方法输出多个值时,我们知道,当方法有返回值时,最后return回来的总是只有一个值,如果我需要将参数a、b同时传入方法并得到两个结果时,怎么办呢?此时就需要使用引用传递了。c#的方法使用了ref关键字,该关键字表示将参数作为引用类型传递,看下面的代码:

   

class Program 
   { 
       static void Main(string[] args) 
       { 
           int a = 10; 
           int b = 50; 
           Console.WriteLine(a); 
           Console.WriteLine(b); 
           ToDouble(ref a,ref b); 
           Console.WriteLine(a); 
           Console.WriteLine(b); 
           Console.ReadKey(); 
       } 
  &

补充:软件开发 , C# ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,