1. 程式人生 > >C#本質論6.0第四章:方法和參數

C#本質論6.0第四章:方法和參數

有助於 異常 名稱 別名 不同的 元素 寫入 轉換 參數順序

方法和參數

方法組合一系列語句以執行特定操作或計算特定結果,它能夠為構成程序的語句提供更好的結構和組織。

  • 方法總是和類型——通常是類關聯。
  • 方法通過實參接收數據,實參由方法的參數或形參定義,參數是調用者用於向被調用的方法傳遞數據的變量。
  • 方法通過返回值將數據返回給調用者。

命名空間

命名空間是一種分類機制,用於組合功能相關的所有類型。

  • 作用:命名空間主要用於按照功能領域組織類型,以便更容易的查找和理解它們。除此之外還有助於防止類型名稱發生沖突。

類型名稱

調用靜態方法時,如果目標方法和調用者不在一個類型中(或者目標方法不在基類中),就需要使用類型名稱限定符。

作用域

一個編程元素的“作用域”是指可以通過它的非限定名稱引用到它的區域。所以,在特定命名空間的某個類型中的方法調用不需要在方法調用名稱中指定該命名空間前綴。

using指令

using指令可將一個或多個命名空間的所有類型“導入”一個文件。

  • using指令不會導入任何嵌套命名空間中的類型。嵌套命名空間必須顯示導入。
  • 在命名空間頂部使用using指令只在聲明的命名空間內有效。
  • using static指令允許省略規定類型的任何成員之前的命名空間和類型名稱。
  • using指令可以為命名空間或類型取一個別名:using CountDownTimer = System.Timers.Timer

調用棧和調用點

每次調用一個新方法,“運行時”都調用一個棧幀,其中包含的內容涉及傳給新調用的實參,新調用的實參、新調用的局部變量以及方法返回時應該從哪裏恢復等。這樣形成的一系列棧幀稱為調用棧。隨著程序復雜度提高,每個方法調用另一個方法時,這個調用棧都會變大。當調用結束時,調用棧會發生收縮,直到調用另一個方法。我們用棧展開描述從調用棧中刪除棧幀的過程。方法調用完畢之後,執行會返回到調用點。

方法的參數

  1. 值參數
    參數默認是傳值(pass by value)的,參數表達式的值會復制到目標參數中。調用棧在一次調用的末尾展開的時候,復制的數據會被丟棄。
  2. 引用參數ref
    傳引用(pass by reference)的方式傳遞變量:使用ref關鍵字使被調用的方法可以用新值來更新調用者的變量。
    如果被調用的方法將參數指定為ref,那麽調用者在調用這個方法的時候,提供的實參應該是附加了ref前綴的變量,而不是值。
    調用者應該對傳引用的變量進行初始化,因為目標方法可能直接從ref參數讀取數據而不先對其進行賦值。
  3. 輸出參數out
    方法經常要獲取一個變量引用,並且只向變量中寫入而不從中讀取,這時安全的做法是以傳引用的方式傳入一個未初始化的局部變量,用out
    修飾參數類型。
    C#語言對別名變量的讀寫有著不同的規定:如果參數被標記為out,編譯器會核實在方法所有正常返回的代碼路徑(不拋出異常的代碼路徑)中,是否都對該參數進行了賦值。
    可用這個方式來克服方法只有一個返回類型的限制,但是這種做法並不好。

參數數組:

  • 當希望一個方法接受數量可變的參數時,請使用參數數組:
    1. 在方法聲明的最後一個參數之前添加params關鍵字。
    2. 將最後一個參數聲明為數組。像這樣聲明了參數數組之後,每個參數都作為參數數組的成員來訪問。
  • 註意:
    • 參數數組不一定是方法的唯一參數,但必須是方法聲明中的最後一個參數。也因此方法最多只能有一個參數數組。
    • 調用者可以指定和參數數組對應的零個實參,這會造成傳遞的參數數組包含零個數據項。
    • 參數數組是類型安全的——實參的類型必須兼容於參數數組中元素的類型。
    • 調用者可以顯式的使用數組,而不是以逗號分隔的參數列表,最終生成的CIL代碼是一樣的。
    • 假如目標方法的實現要求一個最起碼的參數數量,請在方法聲明中顯式指定必須提供的參數。即用int Max(int first, params int[] operands)代替int Max(params int[]operands )以確保至少有一個整數實參傳給Max()

方法重載

假如一個類包含兩個或者更多同名的方法,就會發生方法重載(overloading),重載的方法,參數的數量和數據類型不同。
可以用在一個方法中實現核心功能,其他重載的函數調用這個方法的形式來增強函數復用性。

方法重載是一種操作性多態,如果由於數據的變化導致一個邏輯操作具有許多形式,就會發生多態。

可選參數

聲明方法時把常量值賦給參數,以後調用方法時就不必對每個參數都指定。
private int Attack(Gameobject target=player){}

  • 可選參數一定放在所有必須的參數後面。
  • 默認值必須是常量,或者說必須是能在編譯時確定的值。

命名參數

通過顯式的為一個參數賦值,而不是依據參數順序來決定哪個值賦給哪個參數。
Attack(target: player)

  • 方法重載,可選參數以及命名參數這幾種技術一起使用,將難以一眼看出最終調用的是哪個方法,只有在所有參數(可選參數除外)都恰好有一個對應的是慘,而且該實參具有兼容類型的情況下,才說一個調用適用於一個方法。為了進一步區分方法,編譯器只使用調用者顯式標識的參數,忽略調用者沒有指定的所有可選參數。所以,假如由於一個方法有可選參數,導致兩個方法都適用,編譯器最終選擇的是無可選參數的方法。
  • 當編譯器必須從一系列適用的方法中選擇一個最適合某個特定調用的方法時,會選擇擁有最具體參數類型的那個方法。假如有兩個適用的方法,每個都要求將實參隱式地轉換成形參的類型,最終選擇的是形參類型是更具體的派生類型的那個方法。

用異常實現基本錯誤處理

方法利用異常處理將有關錯誤的信息傳給調用者,同時不需要使用返回值或者顯式提供任何參數。為了通知調用者參數無效,程序會引發異常,中止執行當前分支,跳到調用棧中用於處理異常的第一個代碼塊。對錯誤進行恰當的處理過程被稱為捕獲異常

try與catch關鍵字:

  • try表示塊中的代碼可能引發異常,如果真的引發了異常,那麽某個catch塊要嘗試處理這個異常。
  • try塊之後必須緊跟著一個或多個catch塊。catch 塊可選擇指定異常的數據類型,只要數據類型與異常類型匹配,對應的catch塊就會執行。
  • 處理異常的順序非常重要,catch塊必須按照從最具體到最不具體排列。
  • 無論如何離開try塊,finally塊都會執行,其作用是提供一個最終位置,在其中放入無論是否發生異常都要執行的代碼。其最適合用來執行資源清理。
  • 常規catch(不接受任何參數):等價於獲取object數據類型的catch塊。由於所有類最終都從object派生,所以沒有數據類型的catch塊必須放到最後。

throw關鍵字:

  • C#允許開發人員從代碼中引發異常。如果引發一個異常,會使執行從異常的引發點跳轉到與引發的異常類型兼容的第一個catch塊。

  • 有時catch塊能捕獲到異常,但不能正確或完整的處理它。在這種情況下,可以讓這個catch塊重新引發異常,具體的方法是使用一個單獨的throw 語句,不要在它後面指定任何異常。

C#本質論6.0第四章:方法和參數