c# 方法引數(傳值,傳引用,ref,out,params,可選引數,命名引數)

qq_37591315發表於2018-12-17

c# 方法引數(傳值,傳引用,ref,out,params,可選引數,命名引數)

最近在學習c#的方法引數

原文出自https://blog.csdn.net/susan19890313/article/details/6841541

  

 一、方法引數的型別----值型別和引用型別

       當方法傳遞的引數是值型別時,變數的棧資料會完整地複製到目標引數中即實參和形參中的資料相同但存放在記憶體的不同位置。所以,在目標方法中對形參所做的更改不會對呼叫者的初始變數產生任何影響。

      當方法傳遞的引數是引用型別是,只是將變數的引用複製到目標引數中,實參和形參的引用指向記憶體中的同一位置。所以,在目標方法中對形參所做的更改會影響呼叫者的初始變數。

二、一些特殊的方法引數

1、引用引數---ref (使值型別的變數做方法引數時也可以傳引用)

    一些資料型別(例如類,陣列等引用型別)作為方法的引數時預設是傳引用的,大多數資料型別(例如結構,整數型別等值型別)在作為方法的引數時是傳值的。那麼,如何使值型別的資料作為方法引數時傳遞的也是引用呢?

     方法很簡單,只需要在形參的資料型別前加上關鍵字ref,並在呼叫時相應地實參前也加上關鍵字ref即可。

   例如:  void  Swap( ref String first, ref String second)   {   .......}

               String a="dddd",b="dbbb";

               Swap(ref a,ref b); 注意:ref引數必須是可以賦值的變數

2、輸出引數---out

      除了將引數單向傳入一個方法(傳值),或同時將引數傳入和傳出一個方法(傳引用)之外,還可以將資料從一個方法內部單向傳出方法。為此,程式碼需要使用關鍵字out來修飾引數型別。

     例如:  int x;   //

                  func(out x);     //out引數必須是可以賦值的變數,在呼叫func方法前對out引數賦不賦值都可以。

                void func(out int x ) {};// 在此方法中,在使用out引數x之前必須對其賦值,即使在呼叫此方法前已經對out引數x賦值了,在此方法中仍吧x看做未賦值的變數。

ref引數與out引數都是傳引用,在方法中對引數所做的修改都會傳到呼叫者。區別在於,out引數不接受呼叫者傳來引數的資料值,而是把該引數當做未賦值的引數。

 

 3、引數陣列-----params(可以將相同型別,數量可變的多個引數傳給一個方法)

     引入:一般,引數的數量都是由目標方法宣告所確定。然而,有時我們希望引數的數量是可變的。或許最好的方法是為方法傳一個陣列。然而,這會使呼叫程式碼變得稍微複雜一些,因為需要事先構造一個陣列,再將這個陣列作為引數來傳遞。 為了簡化程式碼,c#提供了一個特殊的關鍵字,它允許在呼叫一個方法是提供數量可變的引數,而不是由方法事先固定好引數的數量。

     示例:

  執行結果:

    示例說明:上述例子中方法func可接受數量可變的引數,不管這些引數是以逗號分隔的,還是作為一個陣列來傳遞的。為了獲得這樣的效果,func方法需要:(1)在方法宣告的最後一個引數之前,新增一個parmas關鍵字。(2)將最後一個引數宣告為一個陣列。

   注意事項:

 @1、引數陣列不一定是方法宣告中的唯一引數。單數必須是最後一個引數。由於只有最後一個引數才可能是引數陣列,所以方法最多隻能有一個引數陣列。

 @2、呼叫者可以為引數陣列指定0個引數,這會造成包含0個資料項的一個陣列。也可以顯示地使用一個陣列,而不是以逗號分隔的引數列表,最終生成的CIL程式碼是一樣的。

 @3、引數陣列是型別安全的------型別必須匹配與陣列指定的型別。

 @4、假如目標方法的實現要求一個最起碼的引數數量,請在方法宣告中顯示指定必須提供的引數。這樣一來,假如要求的引數遺失了,就會導致編譯器報錯,而不需要依賴於執行時錯誤處理。例如:使用int max (int first,params int[] operands)而不是int max(params int[] operands),確保至少有一個值傳給方法max。

4、可選引數:

    從c#4.0開始,增添了對可選引數的支援。宣告方法是將常量賦給引數,以後呼叫方法是就不必每一個引數都指定,若不指定該引數則該引數為方法宣告時指定的初始值。

  例如:

      void  func(int x, int y=2) { Console.WrinteLine(x+y);}

      func(3,2) 和func(3)的輸出結果是相同的。

  注意:

  @1、可選引數一定放在所有必須的引數(沒有預設值的引數)後面。可選引數的數量可以是多個。

  @2、預設值必須是一個常量,或者說必須是編譯時能確定的一個值。

 5、命名引數

   命名引數是c#4.0新增的一個方法呼叫功能。利用命名引數,呼叫者可顯示指定引數名,併為該引數賦一個值而不是像以前那樣只能依據引數順序來決定哪個值賦給哪個引數。

 例如: void  func(int x, int y=2) { Console.WrinteLine(x+y);}     func(y:3,x:2);

               void  display(string firstname, string middlename=default(string), string lastname =default(string));      display(firstname:"susan",lastname: "lili");

注意:如果一個方法有大量引數,而且其中許多都是可選引數(訪問Microsoft COM庫時,這是很常見的情況),那麼命名引數語法肯定能帶來不少便利。但這個便利的代價是犧牲方法介面的靈活性。過去,引數名可以自由更改,不會造成呼叫程式碼無法編譯。但在新增了命名引數後,引數名就成為方法介面的一部分。更改名稱會導致使用命名引數的程式碼無法編譯。

6、方法解析(即當同一個方法呼叫可以適用多個方法,將呼叫哪個方法)

    當同時使用引數陣列,可選引數,命名引數,方法過載等功能時,可能造成同一個方法呼叫可以適用多個方法。

(1)假如由於一個方法有一個可選引數,造成兩個方法都適用(方法過載時可能出現),編譯器最終選擇的將使無可選引數的方法。

(2)假如有兩個適用的方法,每個都需要(對引數)執行一次隱式轉換,就選擇與更具體的型別匹配的方法。例如,如果呼叫者傳遞的是一個int,那麼接受double的方法將優先於接受object的方法。這是由於double比object更具體。

(3)如果有多個適用的方法,但無法從中挑選一個最具唯一性的,編譯器就會報錯,指明呼叫存在歧義。

相關文章