前面已經展示了一些在方法內部創建變量的例子。變量從定義了它的語句開始存在,同一個方法內的後續語句可以使用該變量。換言之,變量只能在創建了之後才能使用。方法執行完畢後,變量也會徹底消失。
假如一個變量能在程序中的一個特定位置使用,就說明該變量具有那個位置的作用域。也就是說,一個變量的作用域(scope)是指能夠使用該變量的程序區域。作用域既作用於方法,也作用於變量。一個標識符(不管它代表變量還是代表方法)的作用域是從聲明明該標識符的那個位置開始的。
定義局部作用域
界定方法主體的起始與結束大括號建立了一個作用域。方法主體中聲明的任何變量都具有那個方法的作用域;一旦方法結束,它們也會消失,而且只能由那個方法內部執行的代碼來訪問。這些變量稱為局部變量(local variable),因為它們局限於聲明它們的那個方法,不能在其他任何方法的作用域中使用。換言之,你不能使用局部變量在不同的方法之間共享信息。例如:
class Example
{
void firstMethod()
{
int myVar;
...
}
void anotherMethod()
{
myVar = 42; // 錯誤 – 變量越界
...
}
}
上述代碼將編譯失敗,因為anotherMethod方法試圖使用一個越界的myVar變量。該變量只能由firstMethod方法中的語句使用。
定義類作用域
界定類主體的起始和結束大括號也建立了一個作用域。在類主體中(但不在一個方法中)聲明的任何變量都具有那個類的作用域。在C#術語中,開發者使用字段(field)一詞來描述由一個類定義的變量。和局部變量不同,你可以使用字段在不同的方法之間共享信息。 例如:
class Example
{
void firstMethod()
{
myField = 42; // ok
...
}
void anotherMethod()
{
myField = 42; // ok
...
}
int myField = 0;
}
變量myField是在類的內部以及firstMethod和anotherMethod方法的外部定義的。所以,myField具有類的作用域,可由類中的所有方法使用。
這個例子中還需要注意另一點。在一個方法中,必須在使用一個變量前聲明它。但字段稍有不同,一個方法能在定義一個字段的語句之前使用那個字段——在這種情況下,編譯器將為你打點一切!
重載方法
如果兩個標識符同名,而且在同一個作用域中聲明,就可以說它們被重載(overloaded)。通常,重載的標識符屬於一個程序bug,會在編譯時被捕捉到並報錯。例如,假定你在同一個方法中聲明了兩個同名的局部變量,就會獲得一個編譯時錯誤。類似地,假如在同一個類中聲明了同名的兩個字段,或者在同一個類中聲明了兩個完全一樣的方法,就會獲得一個編譯時錯誤。這個事實表面上似乎不值一提,因為一切都會被報告為編譯時錯誤。然而,你確實能通過一種方式來重載標識符,而且這種重載不僅是有用的,而且是重要的。
以Console類中的WriteLine方法為例,前面已經使用該方法向屏幕輸出一個字符串。然而,在“代碼和文本編輯器”窗口中輸入WriteLine時,會自動彈出一個“智能感知”列表,其中列出了19個不同的版本!WriteLine方法的每個版本都獲取一套不同的參數。一個實現不獲取任何參數,只是輸出一個空行;另一個實現則獲取一個bool參數,並輸出它的值的字符串形式(true或false);還有一個實現獲取一個小數值,並以字符串的形式輸出它;等。程序編譯時,編譯器會檢查所傳遞的實參的類型,然後調用參數集與之匹配的一個方法版本。下面是一個例子:
static void Main()
{
Console.WriteLine("The answer is ");
Console.WriteLine(42);
}
如果需要針對不同的數據類型執行相同的操作,重載就是一項十分有用的技術。如果不同的實現有不同的參數集,就可以考慮重載一個方法。換言之,每個版本都具有相同的方法名,但具有不同的參數數量或者不同的參數類型。利用這個功能,在調用一個方法時,可以提供一個以逗號分隔的實參列表,而編譯器將根據這些實參的數量和類型,選擇其中的一個匹配的重載版本。但要注意,雖然可以重載一個方法的參數,但不能重載方法的返回類型。也就是說,不能聲明只是返回類型有區別的兩個同名方法(編譯器雖然比較聰明,但還不至於聰明到那種程度)。