• <ruby id="qypib"><blockquote id="qypib"></blockquote></ruby>
    <span id="qypib"></span>

    1. <th id="qypib"><kbd id="qypib"></kbd></th>
      <button id="qypib"></button>
      <s id="qypib"><sub id="qypib"><option id="qypib"></option></sub></s>

    2. IT系統集成商

      系統集成 | 虛擬化應用 | 群暉網(wǎng)絡(luò )存儲 | 視頻會(huì )議 | 數據防泄密 | 技術(shù)運維

      手機: 130-1534-6247   電話(huà): 0351-2396570

      C#函數參數傳遞很容易混淆的概念

      C#中的數據類(lèi)型分為值類(lèi)型引用類(lèi)型兩大類(lèi)。
       
      值類(lèi)型:int,float,bool,char,enum,struct都是值類(lèi)型。
       
      引用類(lèi)型:string,數組,class,接口,委托。其中的string是比較特殊的引用類(lèi)型。C#給它增加個(gè)字符恒定的特性。
       
      值類(lèi)型:直接存儲數據的值,保存在內存中的stack(堆棧)。
       
      引用類(lèi)型:存儲對值的引用,實(shí)際上存儲的就是一個(gè)內存的地址。引用類(lèi)型的保存分成兩塊,實(shí)際值保存在托管堆(heap)中。實(shí)際值的內存地址保存在stack中
       
      C#函數的參數如果不加ref,out這樣的修飾符顯式申明參數是通過(guò)引用傳遞外,默認都是值傳遞
       
      這里要注意的一個(gè)問(wèn)題是,參數的類(lèi)型是值類(lèi)型還是引用類(lèi)型和傳參數時(shí)用值傳遞還是引用傳遞是兩個(gè)不同的概念
       
      假如有void ChangeArray(int [] array) 和void ChangeInt(int a) 這兩個(gè)函數。參數array是引用類(lèi)型,a是值類(lèi)型。但是他們傳遞時(shí)都是按值傳遞。
       
      我們來(lái)舉個(gè)例子說(shuō)明下

      按值傳遞參數:

      class Program
          {
              public static void ChangeInt(int num)
              {
                  num = 100;
              }
       
              public static void ChangeArray(int[] arraynew)
              {
                  arraynew[0] = 10;
                  arraynew= new int[] { 6, 7, 8, 9 };
              }
       
              static void Main(string[] args)
              {
                  int anum = 1;
                  int[] array = { 1, 2, 3 };
                  ChangeInt(anum);
                  ChangeArray(array);
                  Console.WriteLine("value of num: " + anum);
                  Console.Write("value of array: ");
                  foreach (int i in array)
                      Console.Write(i + " ");
              }
       
          }
       
      結果是:value of anum : 1
       
             value of array :10 2 3
       
      可能看到結果會(huì )有點(diǎn)奇怪。我們一般認為值傳遞就是把值拷貝一份,然后不管在函數中對傳入的參數做啥改變,參數之前的值不會(huì )受啥影響,所以anum沒(méi)有變成123,仍然是1
       
      但是array[0]為啥卻變成10了呢?
      參數傳遞,億維訊達
      前面我們有說(shuō)到引用類(lèi)型在內存中是保存為兩個(gè)部分,一個(gè)是stack中的內存地址,另一個(gè)是heap中的實(shí)際值。用時(shí)我們只直接用stack中的值,我們假如stack中的值為0xabcdefgh ,就說(shuō)是array指向它吧。 那么我們按值傳遞時(shí)就是把這個(gè)stack的值拷貝成另一份就假如是arraynew指向它吧。跟拷貝anum的值1一樣。
       
      但是我們操作內存地址這樣的值時(shí)不會(huì )像整數一樣直接操作它,而只會(huì )通過(guò)它去找heap中的實(shí)際值。
       
      于是我們arraynew[0] = 10。改變了實(shí)際上還是heap中數組的值了。 但arraynew= new int [] {6,7,8,9}沒(méi)有對之前傳的array產(chǎn)生影響。這個(gè)操作的意義是在heap中重新開(kāi)辟一塊內存,保存著(zhù)值6,7,8,9。 這這塊內存的地址賦給arraynew,于是它之前的值0xabcdefgh被改寫(xiě)了。但array指的值stack值仍沒(méi)變,仍是0xabcdefgh

      按引用傳遞參數

       
      可以用out或ref顯式指定。它們大部分時(shí)候可以通用,只是有一點(diǎn)細小區別。
       
      先用ref 來(lái)舉例吧,還用上面的例子,只是加個(gè)了關(guān)鍵字ref
       
      class Program
          {
              public static void ChangeInt(ref int num)
              {
                  num = 100;
              }
       
              public static void ChangeArray(ref int[] arraynew)
              {
                  arraynew[0] = 10;
                  arraynew= new int[] { 6, 7, 8, 9 };
              }
       
              static void Main(string[] args)
              {
                  int anum = 1;
                  int[] array = { 1, 2, 3 };
                  ChangeInt(ref anum);
                  ChangeArray(ref array);
                  Console.WriteLine("value of num: " + anum);
                  Console.Write("value of array: ");
                  foreach (int i in array)
                      Console.Write(i + " ");
              }
       
          }
       
      結果是:value of anum : 100
       
             value of array :6 7 8 9
       
      跟按值傳遞的結果完全不同吧
       
      num = 100我們是容易理解。我們再來(lái)說(shuō)下array的值
       
      按引用傳遞時(shí)array指向的stack中的值不會(huì )復制一份,而是直接傳過(guò)去。這樣arraynew[0]= 10這樣賦值時(shí)也同樣改變了heap中 1 2 3 的值,變?yōu)?0 2 3,如果
       
      沒(méi)有arraynew = new int [] {6,7,8,9} 這個(gè)語(yǔ)句,則它的結果跟上面按值傳遞是完全一樣的。但有個(gè)這句話(huà)后就不一樣,我們知道上面說(shuō)了它的含義,在heap中開(kāi)辟一塊新內存
       
      值是6 7 8 9,而array指向的stack的值被改寫(xiě)了,改為指向保存6 7 8 9的內存地址了。那含有10 2 3的那一塊內存其實(shí)還繼續存在,只是沒(méi)有誰(shuí)引用到它了。到時(shí)垃圾回收器會(huì )把它回收的。
       
      補充:
       
      說(shuō)下out 和ref的細小區別
       
      ref 傳進(jìn)來(lái)的參數必須要先賦值。
       
      像上面 的例子中如果這樣寫(xiě)
       
      int num;
       
      ChangeInt(ref int num);
       
      就會(huì )出錯,必須先給num給個(gè)值1。
       
      而且out傳進(jìn)來(lái)的參數可以不先賦值。
       
      out num;
       
      ChangeInt(out int num);是對的
       
      另外還有個(gè)區別就是如果用out的時(shí)候ChangeInt函數中必須有某個(gè)地方給num賦值了,而用ref不一定需要在函數中給num賦值
       
      其實(shí)這樣做的目的很好理解。C#為了確保在任何情況下num必須有個(gè)值,不能為空。
       
      因為用ref,在調用函數前必須保證參數有值,所以在函數中就不必要求它一定再賦值
       
      而用out由于在調用函數前不用保證參數必須有值,所以在函數中必須保證給它個(gè)值
       
      ChangeInt(ref int num)和ChangeInt(out int num)雖然不一樣,但是不同共存,不能當作兩個(gè)不同的函數
       
      而ChangeInt(int num)和上面 的兩個(gè)函數是完全不一樣的,可以放到一起共存
       
      這樣的話(huà)調用的時(shí)候ref ,out這樣的關(guān)鍵字不能省的。必須匹配