類(class)是C#類型中最基礎的類型。類是一個數據結構,將狀態(欄位)和行為(方法和其他函數成員)組合在一個單元中。類提供了用於動態創建類實例的定義,也就是對象(object)。類支持繼承(inheritance)和多態(polymorphism),即派生類能夠擴展和特殊化基類的機制。使用類聲明 ...
類(class)是C#類型中最基礎的類型。類是一個數據結構,將狀態(欄位)和行為(方法和其他函數成員)組合在一個單元中。類提供了用於動態創建類實例的定義,也就是對象(object)。類支持繼承(inheritance)和多態(polymorphism),即派生類能夠擴展和特殊化基類的機制。
使用類聲明可以創建新的類。類聲明以一個聲明頭開始,其組成方式如下:先是指定類的特性和修飾符,後跟類的名字,基類(如果有的話)的名字,以及被該類實現的介面名。聲明頭後面就是類體了,它由一組包含在大括弧({ })中的成員聲明組成。
下麵是一個名為Point的簡單類的聲明:
public class Point
{
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
使用new運算符創建類的實例,它將為新實例分配記憶體,調用構造函數初始化實例,並且返回對該實例的引用。下麵的語句創建兩個Point對象,並且將那些對象的引用保存到兩個變數中:
Point p1 = new Point(0, 0);
Point p2 = new Point(10, 20);
當不再使用對象時,該對象所占的記憶體將被自動回收。在C#中,沒有必要也不可能顯式地釋放對象。
1.成員分類:
(1)時間:
類的成員或者是靜態成員(static member)----屬於類。
實例成員(instance member)----屬於對象。
(2)空間:
屬性。
方法。
索引。
代理。
事件。
嵌套類。
欄位。
2.成員的可訪問性:
類的每個成員都有關聯的可訪問性,它控制能夠訪問該成員的程式文本區域。
public :訪問不受限制。
protected :訪問僅限於包含類或從包含類派生的類型。
internal :訪問僅限於當前程式集。
protected internal :訪問僅限於從包含類派生的當前程式集或類型。
private :訪問僅限於包含類。
3.成員的修飾符:
abstract:指示該方法或屬性沒有實現。
sealed:密封方法。可以防止在派生類中對該方法的override(重載)。不是類的每個成員方法都可以作為密封方法密封方法,必須對基類的虛方法進行重載,提供具體的實現方法。所以,在方法的聲明中,sealed修飾符總是和override修飾符同時使用。
delegate:委托。用來定義一個函數指針。C#中的事件驅動是基於delegate + event的。
const:指定該成員的值只讀不允許修改。
event:聲明一個事件。
extern:指示方法在外部實現。
override:重寫。對由基類繼承成員的新實現。
readonly:指示一個域只能在聲明時以及相同類的內部被賦值。
static:指示一個成員屬於類型本身,而不是屬於特定的對象。即在定義後可不經實例化,就可使用。
virtual:指示一個方法或存取器的實現可以在繼承類中被覆蓋。
new:在派生類中隱藏指定的基類成員,從而實現重寫的功能。 若要隱藏繼承類的成員,請使用相同名稱在派生類中聲明該成員,並用 new 修飾符修飾它。
4.方法
方法(method)是一種用於實現可以由對象或類執行的計算或操作的成員。靜態方法(static method)只能通過類來訪問。實例方法(instance method)則要通過類的實例訪問。
(1).方法的參數
參數用於將值或者引用變數傳遞給方法。當方法被調用時,方法的參數譯註5從指定的自變數(argument)譯註6得到它們實際的值。C#有4種參數:值參數、引用參數、輸出參數和參數數組。
值參數(value parameter)用於輸入參數的傳遞。值參數相當於一個局部變數,它的初始值是從為該參數所傳遞的自變數獲得的。對值參數的修改不會影響所傳遞的自變數。
引用參數(reference parameter)用於輸入和輸出參數的傳遞。用於引用參數的自變數必須是一個變數,並且在方法執行期間,引用參數和作為自變數的變數所表示的是同一個存儲位置。引用參數用ref修飾符聲明。下麵的示例展示了ref參數的使用:
using System;
class Test
{
static void Swap(ref int x, ref int y) {
int temp = x;
x = y;
y = temp;
}
static void Main() {
int i = 1, j = 2;
Swap(ref i, ref j);
Console.WriteLine("{0} {1}", i, j); //輸出 "2 1"
}
}
輸出參數(output parameter)用於輸出參數的傳遞。輸出參數類似於引用參數,不同之處在於調用方提供的自變數初始值無關緊要。輸出參數用out修飾符聲明。下麵的示例展示了out參數的使用:
using System;
class Test {
static void Divide(int x, int y, out int result, out int remainder) {
result = x / y;
remainder = x % y;
}
static void Main() {
int res, rem;
Divide(10, 3, out res, out rem);
Console.WriteLine("{0} {1}", res, rem); //輸出 "3 1"
}
}
參數數組(parameter array)允許將可變長度的自變數列表傳遞給方法。參數數組用params修飾符聲明。只有方法的最後一個參數能夠被聲明為參數數組,而且它必須是一維數組類型。System.Console類的Write和WriteLine方法是參數數組應用的很好的例子。它們的聲明形式如下:
public class Console
{
public static void Write(string fmt, params object[] args) {...}
public static void WriteLine(string fmt, params object[] args) {...}
...
}
(2)虛擬方法、重寫方法和抽象方法
若一個實例方法的聲明中含有virtual修飾符,則稱該方法為虛擬方法(virtual method)。若其中沒有virtual修飾符,則稱該方法為非虛擬方法(nonvirtual method)。
在一個虛擬方法調用中,該調用所涉及的實例的運行時類型(runtime type)確定了要被調用的究竟是該方法的哪一個實現。在非虛擬方法調用中,實例的編譯時類型(compile-time type)是決定性因素。
虛擬方法可以由派生類重寫(override)譯註7實現。當一個實例方法聲明中含有override修飾符時,該方法將重寫所繼承的相同簽名的虛擬方法。虛擬方法聲明用於引入新方法,而重寫方法聲明則用於使現有的繼承虛擬方法專用化(通過提供該方法的新實現)。
抽象(abstract)方法是沒有實現的虛擬方法。抽象方法的聲明是通過abstract修飾符實現的,並且只允許在抽象類中使用抽象方法聲明。非抽象類的派生類需要重寫抽象方法。
(3)方法重載
方法重載(Method overloading)允許在同一個類中採用同一個名稱聲明多個方法,條件是它們的簽名是惟一的。當編譯一個重載方法的調用時,編譯器採用重載決策(overload resolution)確定應調用的方法。重載決策找到最佳匹配自變數的方法,或者在沒有找到最佳匹配的方法時報告錯誤信息。下麵的示例展示了重載決策工作機制。
5.變數(C#中類的變數稱為欄位。類的public變數稱為類的公共欄位)
C#要求局部變數在其值被獲得之前明確賦值(definitely)。
例如,假設前面的變數i的聲明沒有包含初始值,那麼,在接下來對i的使用將導致編譯器報告錯誤,原因就是i在程式中沒有明確賦值。
6.事件
事件是使對象或類能夠提供通知的成員。事件的聲明與欄位的類似,不同之處在於事件聲明包含一個event關鍵字,並且事件聲明的類型必須是委托類型。
在包含事件聲明的類中,事件可以像委托類型的欄位一樣使用(這樣的事件不能是 abstract,而且不能聲明訪問器)。該欄位保存了一個委托的引用,表示事件處理程式已經被添加到事件上。如果尚未添加任何事件處理程式,則該欄位為null。
List類聲明瞭名為Changed的單個事件成員,Changed事件表明有一個新項添加到事件處理程式列表,它由OnChanged虛擬方法引發,它首先檢查事件是否為null(意思是沒有事件處理程式)。引發事件的通知正好等價於調用事件所表示的委托——因此,不需要特殊的語言構件引發事件。
客戶通過事件處理程式(event handler)響應事件。使用“+=”運算符添加或者使用“-=”移除事件處理程式。下麵的示例添加一個事件處理程式到List類的Changed事件:
using System;
class Test
{
static int changeCount;
static void ListChanged(object sender, EventArgs e) {
changCount++;
}
static void Main() {
List names = new List();
names.Changed += new EventHandler(ListChanged);
names.Add("Liz");
names.Add("Martha");
names.Add("Beth");
Console.WriteLine(changeCount); //輸出 "3"
}
}
7. 析構函數
析構函數(destructor)是用於實現析構類實例所需操作的成員。析構函數不能帶參數,不能具有可訪問性修飾符,也不能被顯式地調用。垃圾回收期間會自動調用所涉及實例的析構函數。 在類的繼承中,類的析構函數是不會被繼承的。
垃圾回收器在決定何時回收對象和運行析構函數方面採取寬鬆的策略。特別指出,析構函數的調用時機是不確定的,並且析構函數可能運行在任何線程上。由於這些或者其他原因,只有沒有其他可行的解決方案,類才實現析構函數。
8.構造方法(constructor)
構造函數分為實例構造函數,靜態構造函數。
(1)實例構造函數:用於實例成員的初始化,可以訪問靜態成員和實例成員。
如:
public Class1
{
......
}
(2)靜態構造函數:用於靜態成員的初始化,只可以訪問靜態成員。類的靜態成員屬於類所有,不必生成實例就可以訪問。它是在載入包含類的應用程式時創建的,通常,靜態變數是在定義時就賦初始值的。
如:
public static Class1()
{
......
}
9.常量:其值是在編譯時設定的,必須是數值文字。預設狀態下常量是靜態的(關健字:const)。
如:
public class Class1
{
public const double pi = 3.1415;
}
10.屬性
類的屬性由一個protected(也可以是private)欄位和get和set方法構成:
public class Class1
{
private string ip;//欄位
{
get
{
return ip;
}
set
{
ip=value;
}
};
}
只讀屬性是指省略set方法的屬性,只讀屬性只能讀取,不能設置。
屬性也可以用限定符virtual,override和abstract修飾,功能同其他類的方法。
屬性有一個用處稱為懶惰的初始化(lazy initialization)。即在需要類成員時才對它們進行
初始化。如果類中包含了很少被引用的成員,而這些成員的初始化又會花費大量的時候和系統
資源的話,懶惰的初始化就很有用了。