C#基礎之參數(一) 值參數、引用參數與輸出參數


  要學會各種參數,重點是理解參數參數傳遞的內存原理。理解了內存,各種參數使用的作用、效果等便可以自己分析出來,而不用死記硬背。  

  1.按值傳遞參數(值參數)

    值參數是最常見的一種參數,也很好判斷。在方法聲明與調用時,參數前不加ref或out關鍵字的參數,便是按值傳遞。
    值參數是將實參變量在“棧”中存儲的值復制一份副本,將副本傳遞給方法的形參。
    按值傳遞參數又分為兩種不同情況:傳遞值類型,與傳遞引用類型
    (注意這里的值類型、引用類型是數據類型,而值參數、引用參數是參數傳遞方式。二者不是同一概念,不可混淆。)

    (1)傳遞值類型參數

    示例:

 1 class Program  2  {  3 static void Main(String[] args)  4  {  5 int a = 4;  6 int b = 5;  7  Add(a, b);  8 Console.WriteLine($"a={a},b={b}");  9  } 10 public static void Add(int x, int y) 11  { 12 x += 1; 13 y += 1; 14  } 15 }

    輸出為:

a=4,b=5 

    內存原理:在Add方法中對形參x與y的操作,並不會對實參a與b的值產生影響,因為在Add方法中操作的是a與b的副本。

    (2)傳遞引用類型參數 

    示例1:

 1 class Program  2  {  3 static void Main(String[] args)  4  {  5 Animal a = new Animal() { Age = 1 };  6  Add(a);  7 Console.WriteLine($"a.Age={a.Age}");  8  }  9 public static void Add(Animal animal) 10  { 11 animal.Age += 1; 12  } 13  } 14 class Animal 15  { 16 public int Age { get; set; } 17 }  

    輸出為:

a.Age=2

    內存原理:

    在Add方法中形參animal拿到了實參a在棧中的副本,副本中存儲着對象的地址。所以,animal與a指向了同一個對象。
       這時操作的不是副本,而是副本所指的對象,即操作a所指對象。

    示例2:

    

 1 class Program  2  {  3 static void Main(String[] args)  4  {  5 Animal a = new Animal() { Age = 1 };  6  Add(a);  7 Console.WriteLine($"a.Age={a.Age}");  8  }  9 public static void Add(Animal animal) 10  { 11 animal = new Animal() { Age = 10 }; 12 animal.Age += 1; 13  } 14  } 15 class Animal 16  { 17 public int Age { get; set; } 18 }

    輸出為:

a.Age=1 

    內存原理:

    與示例1不同的是,在示例2中Add方法中改變了animal所指向的對象,指向一個new的Animal對象,此時a仍指向原對象,這時再對animal進行操作,
       便不再會影響實參a所指的對象。

  2.按引用傳遞參數(引用參數)

     形參與實參之前,都要加ref關鍵字。
     需要注意的是,實參在使用之前必須賦值,否則編譯器會報錯。(如下圖)
     此時不再復制實參在棧中的副本,而是將實參在棧中的地址傳給形參,也就是實參與形參共用棧中的值。此時在方法中對形參所做的任何操作,都會影響實參。
     按引用傳遞也分為值類型和引用類型兩種情況。

    (1)傳遞值類型參數

    示例:

    

 1 class Program  2  {  3 static void Main(String[] args)  4  {  5 int a = 4;  6 int b = 5;  7 Add(ref a, ref b);  8 Console.WriteLine($"a={a},b={b}");  9  } 10 public static void Add(ref int x, ref int y) 11  { 12 x += 1; 13 y += 1; 14  } 15 }

 

    輸出為:

a=5,b=6

    內存原理:

    由於a與x,b與y指向了棧中相同的地址,在Add方法中對形參x與y的操作,會影響實參a與b的值。

    (2)傳遞引用類型參數

    示例1:

 

 1 class Program  2  {  3 static void Main(String[] args)  4  {  5 Animal a = new Animal() { Age = 1 };  6 Add(ref a);  7 Console.WriteLine($"a.Age={a.Age}");  8  }  9 public static void Add(ref Animal animal) 10  { 11 animal.Age += 1; 12  } 13  } 14 class Animal 15  { 16 public int Age { get; set; } 17 }

 

    輸出為:

a.Age=2 

    內存原理:

    這時得到的效果,與按值傳遞參數是一樣的,但內存原理卻不相同。

    這時Add方法中形參animal指向的不再是實參a在棧中的副本的地址,而是與a指向了棧中相同的位置。

    示例2:

 1 class Program  2  {  3 static void Main(String[] args)  4  {  5 Animal a = new Animal() { Age = 1 };  6 Add(ref a);  7 Console.WriteLine($"a.Age={a.Age}");  8  }  9 public static void Add(ref Animal animal) 10  { 11 animal = new Animal() { Age = 10 }; 12 animal.Age += 1; 13  } 14  } 15 class Animal 16  { 17 public int Age { get; set; } 18 }

    輸出為:

a.Age=11 

    內存原理:

     這個示例便可以看出與按值傳遞時示例2的不同。

     Add方法中改變了animal所指向的對象,指向一個new的Animal對象,此時a所指向的對象也隨之改變。這是由於形參animal
     與實參a指向的是棧中相同的地址(這個地址中存儲的是對象在堆中的地址)。當棧中存儲的堆地址改變時,animal與a會同時指向新的對象。

  3.輸出參數

    用法:
     (1)形參與實參之前,都要加out關鍵字。
     (2)輸出參數主要是用於函數需要有多個返回值時,作為返回值使用。
    與引用變量相同的是:
     (1)輸出參數也不復制實參在棧中的副本,而是將實參在棧中的地址傳給形參。在這點上,輸出參數與引用參數相同。
     (2)實參必須是可以賦值的變量,而不能是常亮。
    與引用參數不同的是:
     (1)實參在使用之前不必賦值。
     (2)事實上,在使用之前對實參的賦值沒有任何意義,因為在調用方法的最開始,便會將其值抹去,使其成為未賦值的變量。
     (3)在方法返回之前,必須對out參數進行賦值。
    由以上特點所決定的是,輸出參數無法向方法中傳遞信息,其唯一作用便是,當一個參數需要返回多個值時,作為返回值返回。

    示例1:

 1 class Program  2  {  3 static void Main(String[] args)  4  {  5 int a;  6 Add(1, 2, out a);  7  Console.WriteLine(a);  8  }  9 public static bool Add(int x, int y, out int result) 10  { 11 result = x + y; 12 return true; 13  } 14 }

    輸出為:

3 

    引用類型的輸出參數同理,請自行編寫示例代碼。

 

 請繼續閱讀參數學習的下篇:C#基礎之參數(二) 數組參數、可選參數與命名參數

 

 

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM