5.方法,方法
5.1 方法的結構, 方法的大多數內容不僅針對類同樣適用於struct中的方法
1.方法是一塊具有名稱的代碼。可以使用方法的名稱從別的地方執行代碼,也可以把數據傳入方法並接受數據輸出。
2.方法是類的函數成員。方法有兩個主要部分,方法頭和方法體。
1.方法頭指定方法的特征,包括
方法是否返回數據,如果返回,返回什麼類型 (返回值類型)
方法的名稱 (方法的名稱)
哪種類型的數據可以被傳送並源自方法,以及應如何處理該數據。(方法的參數)
2.方法體包含可執行代碼的語句序列。執行從方法體的第一條語句開始,一直到這個方法結束
方法體是一個塊,是大括號闊氣的語句序列,塊可以包含以下幾個項目:
1.本地變量 即 在塊中聲明的變量
2.控制流結構 如 if else 等
3.方法調用 在塊內部調用方法
4.內嵌的塊 如:while循環語句塊
5.2 本地變量
1.本地變量的存在性僅限於創建它的塊及其內嵌的塊
它從聲明它的那一點開始存在
它在它所在的塊完成執行時結束存在
2.可以在方法體內任意位置聲明本地變量,但必須在使用它們前聲明。
對比實例字段和本地變量
實例字段
本地變量
生存期
從實例被創建時開始,直到實例不在被訪問時結束
從它在塊中被聲明的那點開始,在其所在的塊完成執行時結束
隱式初始化
初始化成該類型的默認值
沒有隱式初始化,如果變量在使用之前沒有被賦值,編譯器就會產生一條錯誤信息
存儲區域
類的所有字段都存儲在堆裡,無論他們是值類型還是引用類型
值類型:存儲在棧裡
引用類型:引用存儲在棧裡,數據存儲在堆裡
5.2.1 類型推斷和var關鍵字(var關鍵字是本地變量的萬能偵測類型)
使用var關鍵字有一些重要的條件:
1.只能用於本地變量,不能用於字段
2.只能在變量聲明中包含初始化時使用
3.一點編譯器推斷出變量的類型,他就是固定且不能更改的
5.3 本地常量
1. 本地常量很像本地變量,只是一旦它被初始化,它的值就不能被改變。如同本地變量,本地常量必須聲明在塊的內部
2.常量的兩個最重要的特征如下:
1.常量在聲明中必須初始化
2.常量在聲明後不能改變。
3.常量的核心聲明如下所示。語法與字段或變量的聲明相同,除了下面內容
1.在類型之前增加關鍵字 const
2.必須有初始化語句。初始化值必須在編譯期決定,通常是一個預定義簡單類型或由其組成的表達式。它還可以是null的引用,但他不能是摸個對象的引用,因為對象的引用時在運行時決定的。
說明:關鍵字const 不是一個修飾符, 而是核心聲明的一部分。它必須直接放在類型的前面。如:const Type Identifier = value; value初始化值是必須的。
控制流:
術語控制流指的是程序從頭到尾的執行流程。默認情況下,程序執行持續的從一條語句到下一條語句,控制語句允許你改變執行的順序。
1.選擇語句 這些語句可以選擇哪條語句或語句塊執行
if 有條件的執行一條語句
if ... else 有條件的執行一條或另一個語句
switch 有條件的執行一組語句中的一條
2.迭代語句 這些語句可以在一個語句塊上循環或迭代
for 循環 ——在頂部測試
while 循環——在頂部測試
do循環——在底部測試
foreach——為一組中每個成員執行一次
3.跳轉語句 這些語句可以讓你從代碼塊或方法體內部的一個地方跳到另一個地方。
break 跳出當前循環
continue 到當前循環的底部
goto 到一個命名的語句
return 返回到發起調用的方法
5.6 方法參數:作用:方法的返回值,傳遞方法參數
5.6.1 實參:
當代碼調用一個方法時,形參的值必須在方法的代碼開始執行之前被初始化
1.用於初始化形參的表達式或變量稱作實參(actual parameter,有時也簡稱argument)
2.實參位於方法調用的參數列表中
3.每個實參必須與對應形參的類型相匹配,或者編譯器必須能把實參隱式轉換為哪個類型
5.7值參數和引用參數:
准備知識:
形參:是當我們聲明方法時,為方法聲明的方法參數
實參:當我們調用方法時,傳遞的參數
值類型放在棧中,而引用類型放在堆中而它的引用放在棧中
當我們向調用的方法傳遞參數時,如果參數的類型是值類型,則傳遞的是值類型參數的副本,所以當在調用的方法中改變了傳遞進來參數的值後,當調用的方法運行完之後形參聲明周期結束,但是實參的值並為改變,因為 調用方法時傳遞的是值類型的副本,當參數類型是引用類型時,傳遞的是那個實參復制後的變量,因為是引用類型所以當在調用的方法中將方法引用類型參數的值改變後,實參的值也會變化,原因是它們都指向堆中的同一實體,所以可以通過 ref關鍵字 將實參傳遞進到調用的方法中,而不再是復制後的而是其本身。
值參數和引用參數:
這種將參數復制一下傳遞給調用的方法是值參數也是系統默認的形式,注:這種形式是值參數不要和值類型 相互混淆,而使用ref關鍵字將本身傳遞給調用的方法的是引用參數
值參數需要注意的地方:
在把變量用作實參之前,變量必須被賦值(除非是輸出參數),對於引用類型,變量可以被設置為實際引用或null,在值參數形式下傳遞參數時也可以傳遞具體的值或表達式 如:add(1,2);
引用參數要注意的地方:
使用引用參數時,必須在方法的聲明和調用中都是用ref關鍵字
實參必須是變量,在用作實參前必須被賦值,如果是引用類型變量,可以賦值為一個引用或null值
5.9 輸出參數:
輸出參數用於從方法體內把數據傳出到調用代碼,它們非常類似引用參數,如同引用參數,輸出參數有以下要求。
1.必須在聲明和調用中都是用修飾符,輸出參數的修飾符是out而不是ref。
2.和引用參數相似,實參必須是變量,而不能是其他類型的表達式。這也是有道理的,因為方法需要內存位置保存返回值
與引用參數不同,輸出參數有以下要求:
1.在方法內部,輸出參數在被讀取之前必須被賦值。這意味著參數的初始值是無關的,而且沒有必要再方法調用之前為實參賦值。
2.在方法返回之前,方法內部的任何貫穿的可能路徑都必須為所有輸出參數進行一次賦值
在方法內部要想讀取輸出參數的值,則必須先給給輸出參數賦值,因為輸出參數側重於輸出參數,所以傳遞進來的可能是空。
5.10 參數數組:
1.格式: 一般參數類型都必須嚴格地一個實參對應一個形參。參數數組不一樣,它允許零個或多個實參對應一個特殊的形參。參數數組的重點如下:
1.在一個參數列表中只能有一個參數數組
2.如果有,它必須是列表中的最後一個。
聲明參數數組必須做的事如下:
1.在數據類型前使用params修飾符
2.在數據類型後放置一組空的方括號
例如:voidListInts(paramsint[] inVals){....}
2.方法調用:
有兩個方法提供實參,可以使用如下形式:
1.一個逗號分隔的該數據類型元素的列表。所有元素必須是方法中指定的類型
如:ListInts(10,20,30);
2.一個該數據類型元素的一維數組
如:int[] intArray ={1,2,3};
ListInts( intArray ); //這種是引用參數
請注意:在這些事例中,並不在調用時使用params修飾符。參數數組中修飾的使用並不適用於其他參數類型的模式
1.其他參數類型要麼使用修飾符,要麼不使用修飾符。
1.值參數的聲明和調用都不帶修飾符
2.引用參數和輸出參數在兩個地方都需要修飾符。
2.params修飾符的用法總結如下。
1.在聲明中需要修飾符
2.在調用中不允許有修飾符
延伸式
方法調用的第一種形式有時被稱為延伸式,這種形式在調用中使用分離的實參
例如,下面代碼中的方法ListInts的聲明可以匹配它下面所有的方法調用,雖然他們有不同數目的實參。
voidListInts(paramsint[] inVals){...}//方法聲明
ListInts();//0實參
ListInts(1,2,3);//3實參
ListInts(4,5,6,7);//4實參
ListInts(8,9,10,11,12);//5實參
- //以上這些事值參數
使用一個為參數數組分離實參的調用時,編譯器做下面的事。
1.接受實參列表,用它們在堆中創建並初始化一個數組
2把數組的引用保存到棧中的形參裡
3.如果在對應的形參數組的位置沒有實參,編譯器會創建一個有0個元素的數組來使用
注意:在寫參數數組方法實現的時候要首先判斷是否為空和長度是否大於0
publicvoidListInts(paramsint[] a){
if(a !=null&& a.Length!=0)
{
for(int i =0; i < a.Length; i++)
{
a[i]= a[i]*10;
Console.WriteLine(a[i]);
}
}
}
關於參數數組,需要記住的重要一點是當數組在堆中被創建時,實參的值被復制到數組中。在這方面,它們向值參數。
1.如果數組參數是值類型,那麼值被賦值,實參不受方法內部的影響。
2.如果數組參數時引用類型,那麼引用被賦值,實參引用的對象可以收到方法內部的影響。
參數類型總結:
參數類型語法使用總結
參數類型
修飾符
是否在聲明時使用
是否在調用時使用
執 行
值
無
系統把實參的值復制到形參
引用
ref
是
是
形參是實參的別名
輸出
out
是
是
形參是實參的別名
數組
params
是
否
允許傳遞可變數目的實參到方法
5.12 方法重載
1.一個類中可以有一個以上的方法擁有相同的名稱,這叫做方法的重載(method overload)。使用相同名稱的每個方法必須有一個和其他方法不相同的簽名(signature)。
2.方法的簽名由下列信息組成,它們在方法聲明的方法頭中:
1.方法的名稱
2.參數的數目
3.參數的數據類型和順序
4.參數的修飾符
3.注意:返回類型不是簽名的一部分
5.13 命名參數,調用方法的時候可以改變形參的位置賦值
1.從c#4.0開始,只要顯示指定參數的名字,就可以以任意順序在方法調用中列出實參。
1.方法的聲明不變
2.在調用的時候,形參的名字後面跟著冒號和實際的參數值或表達式,如:
//聲明一個方法
publicvoidAdd(int num1,int num2,int num3){...}
//調用方法
Add( num2:1, num3:2, num1:3);
5.14 可選參數
1. c#4.0引入的另一個特性叫做可選參數。所謂的可選參數就是我們可以在調用方法的時候包含這個參數,也可以省略它。
2.為表名某個參數是可選的,你需要在方法聲明的時候為參數提供默認值。指定默認值的語法和初始化本地變量的語法一樣。
如:
//聲明可選參數的方法
publicintAdd(int num1,int num2 =0)
{
...
}
//調用可選參數的方法
//第一種
Add(1,2);
//第二種
Add(1); // 當不給可選的參數賦值時,則可選參數使用默認的值
3.對於可選參數的聲明,我們需要知道如下幾個重要事項
1.不是所有的參數類型都可以作為可選參數。
1.只要值類型的默認值在編譯的時候可以確定,就可以使用值類型作為可選參數。
2.只要在默認值是null的時候,引用類型才可以用作可選參數來使用。
參數類型
數
據
類
型
值
ref
out
params
值類型
是
否
否
否
引用類型
只允許為null的默認值
否
否
否
可選參數只能是值參數類型
2.所有必填參數必須在可選參數聲明之前聲明。如果有params參數,必須在所有可選參數之後聲明
如:(int x , decimal y , ..... int op1 = 17 , double op2 = 36 , ..... params int[] intVals)
當方法中的可選參數多的時候,我們不能隨意省略可選參數的組合,因為在很多情況下這麼做會導致使用哪些可選參數不明確,規則如下、 :
1. 你必須從可選參數列表的最後開始省略,一直到列表開頭。 也就是說,你可以省略最後一個可選參數,或是最後n個參數,但是不可以隨意選擇省略任意的可選參數,省略必須從最後開始。
2.如果需要隨意省略可選參數列表中的可選參數,而不是從列表中的最後開始,那麼必須使用可選參數的名字來消除賦值的歧義。也就是說,需要結合命名參數和可選參數可行
5.15 棧幀
在調用方法的時候,內存從棧的頂部開始分配,保存和方法關聯的一些數據項。這塊內存叫做方法的棧幀(stack frame)。
1.棧幀包含的內存保存如下內容。
1.返回地址,也就是在方法推出的時候繼續執行的位置。
2.這些參數分配的內存,也就是方法的值參數,或者還可能是參數的數組(如果有的話)。
3.各種和方法調用相關的其他管理數據項
2.在方法調用時,整個棧幀都會壓入棧。
3.在方法推出的時候,整個棧幀都會從棧上彈出,彈出棧幀有時候也叫做 棧展開 (unwind).
5.16 遞歸 要理解遞歸看看棧幀
除了調用其他方法,方法也可以調用自身,這叫做遞歸。
classProgram
{
publicstaticvoidCount(int num)
{
if(num ==0)
{
return;
}
Count(num-1);
Console.WriteLine(num);
}
staticvoidMain(string[] args)
{
Count(2);
}
}
17. 輸出的結果 1 2
來自為知筆記(Wiz)