CSharp(C#)語言_第三章(方法)

3.1 方法的結構

        方法是一塊具有名稱的代碼,可以使用方法的名稱從別的地方執行代碼,也可以把數據傳入方法並接收數據輸出

        方法是類的函數成員,方法有兩個主要部分:方法頭方法體

方法頭指定方法的特徵,包括:
        方法是否返回數據,如果返回,返回什麼類型
        方法的名稱
        哪種類型的數據可以傳入方法或返回方法,已經應如何處理這些數據

方法體包含可執行代碼的語句序列,執行過程從方法體的第一條語句開始,一直到整個方法結束

3.2 方法體內部代碼的執行

        方法體是一塊,由大括號括起來的語句序列 ,可以包含以下項目

        本地變量
        控制流結構
        方法調用
        內嵌的塊

3.3 本地變量

        本地變量經常是用於保存本地的或臨時的計算數據

本地變量的存在性和生存期僅限於創建它的塊及其內嵌的塊
        它從聲明它的那一點開始存在
        它在塊完成執行時結束存在
可以在方法體內任意位置聲明本地變量,但必須在使用它們之前聲明

3.3.1 var關鍵字

        var關鍵字並不是特定類型變量的符號。它只是句法上的速記,表示任何可以從初始化語句的右邊推斷出的類型。在第一個聲明中,它是int的速記;在第二個聲明中,它是MyExcellentClass的速記。前文中使用顯式類型名的代碼片段和使用var關鍵字的代碼片段在語義上是等價的

使用var關鍵字有一些重要的條件:
        只能用於本地變量,不能用於字段
        只能在變量聲明中包含初始化時使用
        一旦編譯器推斷出變量的類型,它就是固定且不能更改的

3.3.2 嵌套塊中的本地變量

方法體內部可以嵌套其他的塊
        可以有任意數量的塊,並且它們既可以是順序的也可以更深層嵌套的。塊可以嵌套到任何級別
        本地變量可以在嵌套塊的內部聲明,並且和所有的本地變量一樣,它們的生存期和可見性僅限於聲明它們的塊及其內嵌塊

3.4 本地常量

        本地常量很像本地變量,只是一旦被初始化,它的值就不能改變了。如同本地變量,本地常量必須聲明在塊的內部

常量的兩個最重要的特徵如下:
        常量在聲明時必須初始化
        常量在聲明後不能改變

常量的核心聲明如下所示。語法與字段或變量的聲明相同,除了下面內容
        在類型之前增加關鍵字const
        必須有初始化語句。初始化值必須在編譯期決定,通常是一個預定義簡單類型或由其組成的表達式。它還可以是null引用,但它不能是某對象的引用,因爲對象的引用是在運行時決定的

3.5 控制流

        方法包含了大部分組成程序行爲的代碼。剩餘部分在其他的函數成員中,如屬性和運算符
        術語控制流指的是程序從頭到尾的執行流程。默認情況下,程序執行持續地從一條語句到下一條語句,控制流語句允許你改變執行的順序

    選擇語句 這些語句可以選擇哪條語句或語句塊來執行
        ■ if 有條件地執行一條語句
        ■ if…else 有條件地執行一條或另一條語句
        ■ switch 有條件地執行一組語句中的某一條

    迭代語句 這些語句可以在一個語句塊上循環或迭代
        ■ for 循環——在頂部測試
        ■ while 循環——在頂部測試
        ■ do 循環——在底部測試
        ■ foreach 爲一組中每個成員執行一次

    跳轉語句 這些語句可以讓你從代碼塊或方法體內部的一個地方跳到另一個地方
        ■ break 跳出當前循環
        ■ continue 到當前循環的底部
        ■ goto 到一個命名的語句
        ■ return 返回到調用方法繼續執行

3.6 方法調用

        可以從方法體的內部調用其他方法

英文中call(調用)方法和invoke方法是同義的
調用方法時要使用方法名並帶上參數列表

調用方法時的動作順序
(1)當前方法的執行在調用點被掛起
(2)控制轉移到被調用方法的開始
(3)被調用方法執行直到完成
(4)控制回到發起調用的方法

3.7 返回值

        方法可以向調用代碼返回一個值。返回的值被插入到調用代碼中發起調用的表達式所在的位置
        ■ 要返回值,方法必須在方法名前面聲明一個返回類型
        ■ 如果方法不返回值,它必須聲明void返回類型

3.8 返回語句和 void方法

        void方法不需要返回語句。當控制流到達方法體的關閉大括號時,控制返回到調用代碼,並且沒有值被插入到調用代碼中。
        不過,當特定條件符合的時候,我們常常會提前退出方法以簡化程序邏輯
        可以在任何時候使用下面形式的返回語句退出方法,不帶參數
                return;
        這種形式的返回語句只能用於用void聲明的方法

3.9 參數

        方法是可以被程序中很多地方調用的命名代碼單元,它能把一個值返回給調用代碼。返回一個值的確有用,但如果需要返回多個值呢?還有,能在方法開始執行的時候把數據傳入方法也會有用。參數就是允許你做這兩件事的特殊變量

3.9.1 形參

        形參是本地變量,它聲明在方法的參數列表中,而不是方法體中
        因爲形參是變量,所以它們有類型和名稱,並能被寫入和讀取
        和方法中的其他本地變量不同,參數在方法體的外面定義並在方法開始之前初始化(但有一種類型例外,稱爲輸出參數)
        參數列表中可以有任意數目的形參聲明,而且聲明必須用逗號隔開
形參在整個方法體內使用,在大部分地方就像其他本地變量一樣

3.9.2 實參

        當代碼調用一個方法時,形參的值必須在方法的代碼開始執行之前被初始化
        用於初始化形參的表達式或變量稱作實參(actual parameter,有時候也稱argument)
        實參位於方法調用的參數列表中
        每一個實參必須與對應形參的類型相匹配,或是編譯器必須能夠把實參隱式轉換爲那個類型
        當方法被調用的時候,每個實參的值都被用於初始化相應的形參,方法體隨後被執行

        實參的數量必須和形參的數量一致,並且每個實參的類型也必須和所對應的形參類型一致。這種形式的參數叫做位置參數

3.10 值參數

        參數有幾種,各自以略微不同的方式從方法傳人或傳出數據。你到現在一直看到的這種類型是默認的類型,稱爲值參數(value parameter)
        使用值參數,通過將實參的值複製到形參的方式把數據傳遞給方法。方法被調用時,系統做如下操作:
        ■ 在棧中爲形參分配空間
        ■ 將實參的值複製給形參
值參數的實參不一定是變量。它可以是任何能計算成相應數據類型的表達式
在把變量用作實參之前,變量必須被賦值。對於引用類型,變量可以被設置爲一個實際的引用或null

3.11 引用參數

第二種參數類型稱爲引用參數
        ■使用引用參數時,必須在方法的聲明和調用中都使用ref修飾符
        ■實參必須是變量,在用作實參前必須被賦值。如果是引用類型變量,可以賦值爲一個引用或null

        對於值參數,系統在棧上爲形參分配內存,相反,引用參數具有以下特徵
        ■ 不會爲形參在棧上分配內存
        ■ 實際情況是,形參的參數名將作爲實參變量的別名,指向相同的內存位置
        由於形參名和實參名的行爲就好像指向相同的內存位置,所以在方法的執行過程中對形參作的任何改變在方法完成後依然有效(表現在實參變量上)

3.12 引用類型作爲值參數和引用參數

        在前幾節中我們看到了,對於一個引用類型對象,不管是將其作爲值參數傳遞還是作爲引用參數傳遞,我們都可以在方法成員內部修改它的成員。不過,我們並沒有在方法內部設置形參本身。本節來看看在方法內設置引用類型形參時會發生什麼
        ■ 將引用類型對象作爲值參數傳遞 如果在方法內創建一個新對象並賦值給形參,將切斷形參與實參之間的關聯,並且在方法調用結束後,新對象也將不復存在
        ■ 將引用類型對象作爲引用參數傳遞 如果在方法內創建一個新對象並賦值給形參,在方法結束後該對象依然存在,並且是實參所引用的值

3.13 輸出參數

輸出參數用於從方法體內把數據傳出到調用代碼,它們的行爲與引用參數非常類似。如同引用參數,輸出參數有以下要求
        ■ 必須在聲明和調用中都使用修飾符。輸出參數的修飾符是out而不是ref
        ■ 和引用參數相似,實參必須是變量,而不能是其他類型的表達式。這是有道理的,因爲方法需要內存位置保存返回值

        與引用參數類似,輸出參數的形參擔當實參的別名。形參和實參都是同一塊內存位置的名稱。顯然,方法內對形參的任何改變在方法執行完成之後通過實參變量都是可見的

        與引用參數不同,輸出參數有以下要求
        ■ 在方法內部,輸出參數在能夠被讀取之前必須被賦值。這意味着參數的初始值是無關的,而且沒有必要在方法調用之前爲實參賦值
        ■ 在方法返回之前,方法內部貫穿的任何可能路徑都必須爲所有輸出參數進行一次賦值因爲方法內的代碼在讀取輸出變量之前必須對其寫入,所以不可能使用輸出參數把數據傳入方法。事實上,如果方法中有任何執行路徑試圖在輸出參數被方法賦值之前讀取它,編譯器就會產生一條錯誤信息

3.14 參數數組

        參數類型都必須嚴格地一個實參對應一個形參。參數數組則不同,它允許零個或多個實參對應一個特殊的形參。參數數組的重點如下:

        ■ 在一個參數列表中只能有一個參數數組
        ■ 如果有,它必須是列表中的最後一個
        ■ 由參數數組表示的所有參數都必須具有相同的類型。

聲明一個參數數組必須做的事如下:
        ■ 在數據類型前使用params修飾符
        ■ 在數據類型後放置一組空的方括號

類型名後面的空方括號指明瞭參數是一個整數數組
        ■ 數組是一組整齊的相同類型的數據項
        ■ 數組使用一個數字索引進行訪問
        ■ 數組是一個引用類型,因此它的所有數據項都保存在堆中

3.15 方法重載

一個類中可以有一個以上的方法擁有相同的名稱,這叫做方法重載(method overload)
使用相同名稱的每個方法必須有一個和其他方法不相同的簽名(signature)
    方法的簽名由下列信息組成,它們在方法聲明的方法頭中:
        ■ 方法的名稱
        ■ 參數的數目
        ■ 參數的數據類型和順序
        ■ 參數修飾符
    返回類型不是簽名的一部分,而我們往往誤認爲它是簽名的一部分
形參的名稱也不是簽名的一部分

3.16 命名參數

        至今我們所有用到的參數都是位置參數,也就是說每一個實參的位置都必須與相應的形參位置一一對應
        此外,C#還允許我們使用命名參數(namedparameter)。只要顯式指定參數的名字,就可以以任意順序在方法調用中列出實參
        ■ 方法的聲明沒有什麼不一樣。形參已經有名字了
        ■ 不過在調用方法的時候,形參的名字後面跟着冒號和實際的參數值或表達式

在調用的時候,你可以既使用位置參數又使用命名參數,但如果這麼做,所有位置參數必須先列出來

3.17 可選參數

        C#還允許可選參數(optional parameter)。所謂可選參數就是我們可以在調用方去的時候包含這個參數,也可以省略它

3.18 棧幀

        在調用方法的時候,內存從棧的頂部開始分配,保存和方法關聯的一些數據項。這塊內存叫做方法的棧幀(stackframe)

棧幀包含的內存保存如下內容:
    ■返回地址,也就是在方法退出的時候繼續執行的位置
    ■這些參數分配的內存,也就是方法的值參數,或者還可能是參數數組(如果有的話)
    ■各種和方法調用相關的其他管理數據項

    在方法調用時,整個棧幀都會壓入棧。
    在方法退出的時候,整個棧幀都會從棧上彈出。彈出棧幀有的時候也叫做棧展開
(unwind)

3.19 遞歸

方法調用自身,叫做遞歸

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章