国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

[CLR via C#]9. 參數

2019-11-17 03:21:57
字體:
來源:轉載
供稿:網友

[CLR via C#]9. 參數

一、可選參數和命名參數

  在設計一個方法的參數時,可為部分或全部參數分配默認值。然后,調用這些方法的代碼時可以選擇不指定部分實參,接受默認值。此外,調用方法時,還可以通過指定參數名稱的方式為其傳遞實參。比如:

internal static class PRogram {   private static Int32 s_n = 0;      private static void M(Int32 x=9, String s = "A",DateTime dt = default(DateTime), Guid guid = new Guid()) {      Console.WriteLine("x={0}, s={1}, dt={2}, guid={3}, x, s, dt, guid");   }       public static void Go() {      // 1.等同于: M(9, "A", default(DateTime), new Guid());      M();       // 2. 等同于: M(8, "X", default(DateTime), new Guid());      M(8, "X");       // 3. 等同于: M(5, "A", DateTime.Now, Guid.NewGuid());      M(5, guid: Guid.NewGuid(), dt: DateTime.Now);       // 4. 等同于: M(0, "1", default(DateTime), new Guid());      M(s_n++, s_n++.ToString());       // 5. 等同于s: String t1 = "2"; Int32 t2 = 3;      //             M(t2, t1, default(DateTime), new Guid());      M(s: (s_n++).ToString(), x: s_n++);   }}
    在定義的方法中,如果為部分參數指定了默認值,需注意下述原則:  1)可以為方法、構造器方法和有參屬性(C#索引器)的參數指定默認值。還可為屬于委托定義一部分的參數指定默認值。然后,在調用該委托類型的一個變量時,可以省略實參,以接受默認值。  2)有默認值的參數必須放在沒有默認值的所有參數之后。換言之,一旦定義了一個有默認值的參數,它右邊的所有參數也必須有默認值。但有個例外:"參數數組"這種參數必須放在所有參數(包括有默認值的這些)之后,而且數組本身不能有一個默認值。  3)默認值必須是編譯時能確定的常量值。這些參數的類型可以是C#認定的基元類型,還包括枚舉類型,以及設為null的任何引用類型。對于任何值類型的一個參數,可將默認值設為值類型的一個實例,并讓它的所有字段都包含零值。可以用default關鍵字或者new關鍵字來表達這個意思。如在M方法中設置dt參數和guid參數的默認值,就是用的這兩種語法。  4)注意不要重新命名(即修改)參數變量名稱。否則,任何調用者如果以傳參數名的方式傳遞實參,都必須修改它們的代碼。  5)如果方法是從模塊的外部調用的,更改參數的默認值具有潛在的危險性。調用方會在它的調用中嵌入默認值。如果以后更改參數的默認值,但沒有重新編譯調用方所在的代碼,它在調用你的方法時就會傳遞就得默認值。可考慮將默認值設為0/null作為哨兵值(起到占位子作用)使用。  6)如果參數使用ref或out關鍵字進行了標識,就不能設置默認值。因為沒有辦法為這些參數傳遞一個有意義的默認值。  使用可選或命名參數調用一個方法時,還要注意下述原則:  1)實參可按任何順序傳遞;但是,命名實參只能出現在實參列表的尾部。  2)可按名稱將實參傳給沒有默認值的參數。  3)C#不允許省略都好之間的實參,比如M(1, ,DateTime.Now)。  4)如果參數需要ref/out,為了以傳參數名的方式傳遞實參,請使用下面語法:
 // 方法聲明 private static void M(ref Int32 x) { ... } // 方法調用 Int32 a = 5; M(x: ref a); .....

  在C#中,一旦為某個參數分配了一個默認值,編譯器就會在內部像該參數應用一個定制attibute,即System.Runtime.InteropServices.OptionalAttribute。這個attribute會在最終生成的文件的元數據中持久性地存儲下來。此外,編譯器還會向參數引用一個名為System.Runtime.InteropServices.DefaultParameterValueAttribute的attribute,并將這個attribute持久性存儲在最終文件的元數據中,然后,會向DefaultParameterValueAttribute的構造器中傳遞你在源代碼中指定的常量值。之后,一旦編譯器發現一個方法調用缺失了部分實參,就可以確定省略的是可選的實參,并從元數據中提取它們的默認值,將這些值自動嵌入調用中。  之后,一旦編譯器發現一個方法調用缺失了部分實參,就可以確定省略的是可選的實參,并從元數據中提取它們的默認值,并將這些值自動嵌入調用中。

二、隱式類型的局部變量

  針對一個方法中的隱式類型的局部變量,C#允許根據初始化表達式的類型來判斷它的類型。

private static void ImplicitlyTypedLocalVariables() {      var name = "Jeff";      ShowVariableType(name);    // 類型是: System.String       // var n = null;           // 錯誤      var x = (Exception)null;   // 可以這樣寫,但沒意義      ShowVariableType(x);       // 類型是: System.Exception       var numbers = new Int32[] { 1, 2, 3, 4 };      ShowVariableType(numbers); // 類型是: System.Int32[]       // 針對復雜類型,可減少打字量      var collection = new Dictionary<String, Single>() { { ".NET", 4.0f } };       // 類型是: System.Collections.Generic.Dictionary`2[System.String,System.Single]      ShowVariableType(collection);       foreach (var item in collection) {         // 類型是: System.Collections.Generic.KeyValuePair`2[System.String,System.Single]         ShowVariableType(item);      }   }
  隱式類型的局部變量是局部變量,不能用它聲明方法的參數。也不能聲明一個類型的字段。  用var聲明的局部變量只是一種簡化語法,它要求編譯器根據一個表達式推斷具體的數據類型。var關鍵字只能用于聲明方法內部的局部變量,而dynamic關鍵字可用于局部變量,字段和參數。表達式不能轉型為var,但可以轉型為dynamic。必須實現初始化化var聲明的變量,但無需初始化用dynamic聲明的變量。三、以傳遞引用的方式向方法傳遞參數  默認情況下,CLR假定所有的方法參數都是傳值的。  傳遞引用類型的對象時,對一個對象的引用(或者說指向對象的指針)會傳給方法。但這個引用(或指針)本身是以傳值方式傳給方法的。這意味著方法能修改對象,而調用者能看到這些修改。對于值類型的實例,傳給方法的是實例的一個副本,這意味著方法將獲取它專用的一個值類型實例副本,調用中的實例不受影響。  CLR中允許以傳引用而非傳值的方式傳遞參數。在C#中,這是用關鍵字out和ref。這兩個關鍵字都告訴C#編譯器生成的元數據來指明該參數時傳引用的。編譯器將生成代碼來傳遞參數的地址,而不是傳遞參數本身。  從CLR角度看,關鍵字out和ref完全一致。這就是說,無論用哪個關鍵字,都會生成相同的IL代碼。另外,元數據也幾乎一致。只有一個bit除外,它用于記錄聲明方法時指定的是out還是ref。  C#編譯器是將者兩個關鍵字區別對待的,而且這個區別決定了有哪個方法負責初始化所引用的對象。  如果方法的參數用out來標記,表明不指望調用者在調用方法之前初始化好了對象。被調用的方法不能讀取參數的值,而且在返回前必須向這個值寫入。相反,如果方法的參數用ref來標記,調用者就必須在調用方法前初始化參數的值,被調用的方法可以讀取值或者寫入值。  為值類型使用out和ref,效果等同于以傳值的方式傳遞引用類型。對于值類型,out和ref允許方法操縱單一的值類型實例。調用者必須為實例分配內存,被調用者則操縱該內存中的內容。  對于引用類型,調用代碼為一個指針分配內存(該指針指向一個引用類型的對象),被調用者則操縱這個指針。正因為如此,僅當方法"返回"對"方法知道的一個對象"的引用時,為引用類型提供out和ref才有意義。四、向方法傳遞可變數量的參數  有的時候,開發人員想定義一個方法來獲取可變數量的參數。為了聲明方法接受可變數量的參數,如下:
   private static Int32 Add(params Int32[] values) {      Int32 sum = 0;      for (Int32 x = 0; x < values.Length; x++)         sum += values[x];      return sum;   }

  params關鍵字只能應用于方法參數列表的最后一個參數。

  我們調用時可以這樣:
 //顯示 "15" Console.WriteLine(Add(new Int32[] { 1, 2, 3, 4, 5 }));

  也可以這樣:

 // 顯示 "15" Console.WriteLine(Add(1, 2, 3, 4, 5));
  由于params關鍵字的存在,所以可以這么做。params關鍵字告訴編譯器向參數引用System.ParamArrayAttribute的一個實例。  只有方法的最后一個參數才能用params關鍵字(ParamArrayAttribute)來標記。另外,這個參數只能標識任意類型的一個一位數組。可為這個參數傳遞null值,或傳遞對包含另個元素的一個數組的引用。
 // 顯示"0" Console.WriteLine(Add()); Console.WriteLine(Add(null));
  那么如果寫一個方法來獲取任意數量、任意類型的參數呢?只需要修改方法原型,讓它獲取一個Object[]而不是Int32[]。比如
private static void DisplayTypes(params Object[] objects) {      foreach (Object o in objects)         Console.WriteLine(o.GetType());   }

五、參數和返回類型的指導原則

  1)聲明方法的參數類型時,應盡量指定最弱的類型,最好是接口而不是基類。  例如,如果要寫一個方法處理一組數據項,最好是用接口(比如IEnumerable<T>)來聲明方法的參數,而不要使用強數據類型(比如List<T>)或者更強的接口類型(比如ICollection<T>或IList<T>):
    //好    public void MainpulateItems<T>(IEnumerable<T> collection) { ... }    //不好        public void MainpulateItems<T>(List<T> collection) { ... }     //好:該方法使用弱參數類型    public void ProcessBytes(Stream someStream) { ... }    //不好:該方法使用強參數類型    public void ProcessBytes(FileStream someStream) { ... }

  2)一般最好將方法的返回類型聲明為最強的類型,以免受限于特定類型。例如:

    //好:該方法使用強返回值類型    public FileStream ProcessBytes() { ... }    //不好:該方法使用弱返回值類型    public Stream ProcessBytes() { ... }
  第一個方法是首選的,它允許方法的調用者選擇將返回對象視為一個FileStream對象或者一個Stream對象。但是,第二個方法要求調用者將返回對象視為一個Stream對象。總之,確保調用者在調用方法時有盡量大的靈活性,使方法的應用范圍更大。

六、常量性

CLR沒有提供對常量參數/對象的支持。
上一篇:ASCII碼表

下一篇:簡單的日志管理代碼

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 连南| 通江县| 琼结县| 措勤县| 桦甸市| 新巴尔虎右旗| 屏东县| 安西县| 平原县| 达州市| 富民县| 徐闻县| 古浪县| 黄龙县| 收藏| 罗城| 绩溪县| 滁州市| 喀喇| 关岭| 梁平县| 兴业县| 多伦县| 屏山县| 鄂伦春自治旗| 克东县| 浏阳市| 江川县| 驻马店市| 温州市| 临安市| 彰化县| 民乐县| 临湘市| 溧阳市| 原平市| 徐州市| 郯城县| 治多县| 吉安县| 威海市|