53
1 第一章 第一章 第一章 第一章 C#語言基礎 語言基礎 語言基礎 語言基礎 本章介紹 C#語言的基礎知識,希望具有 C 語言的讀者能夠基本掌握 C#語言,以此為基礎, 能夠進一步學習用 C#語言編寫 Window 應用程序和 Web 應用程序。當然僅靠一章的內容就完 全掌握 C#語言是不可能的,如需進一步學習 C#語言,還需要認真閱讀有關 C#語言的專著。 1.1 C#語言特點 語言特點 語言特點 語言特點 Microsoft.NET(以下簡稱·NET)框架是微軟提出的新一代 Web 軟件開發模型,C#語言是·NET 框架中新一代的開發工具。C#語言是一種現代、物件導向的語言,它簡化了 C++語言在類、命 名空問、方法多載和異常處理等方面的操作,它摒棄了 C++的複雜性,更易使用,更少出錯。 它使用組件編程,和 VB 一樣容易使用。C#語法和 C++JAVA 語法非常相似,如果讀者用過 C++JAVA,學習 C#語言應是比較輕鬆的。 C#語言編寫的源碼程式,必須用 C#語言編譯器將 C#源碼程式編譯為中間語言(Microsoft Intermediate Language, MSIL)代碼,形成副檔名為 exe dll 文件。中間語言代碼不是 CPU 可執 行的機器碼,在程序執行時,必須由通用語言執行環境(Common Language RuntimeCLR)中的 即時編譯器(Just In TimeJIT)將中間語言代碼翻譯為 CPU 可執行的機器碼,由 CPU 執行。CLR C#語言中間語言代碼執行提供了一種執行時環境,C#語言的 CLR JAVA 語言的虛擬機類 似。這種執行方法使執行速度變慢,但帶來其它一些好處,主要有: 通用語言規範(Common Language SpecificationCLS).NET 系統包括如下語言:C#C++VBJ#,他們都遵守通用語言規範。任何遵守通用語言規範的語言源程序,都可編譯為相 同的中間語言代碼,由 CLR 負責執行。只要為其它操作系統編製相應的 CLR,中問語言代 碼也可在其它系統中執行。 自動記憶體管理:CLR 內建垃圾收集器,當變數實例的生命周期結束時,垃圾收集器負責 收回不被使用的實例佔用的記憶體空間。不必像 C C++語言,用語句在堆積中建立的實 例,必須用語句釋放實例佔用的記憶體空間。也就是說,CLR 具有自動記憶體管理功能。 跨語言處理:由於任何遵守通用語言規範的語言源程序都可編譯為相同的中間語言代碼, 不同語言設計的組件,可以互相通用,可以從其它語言定義的類衍生出本語言的新類。由 於中間語言代碼由 CLR 負責執行,因此異常處理方法是一致的,這在調試一種語言調用另 一種語言的子程序時,顯得特別方便。 增加安全:C#語言不支援指標,一切對記憶體的存取者都必須通過物件的參照變數來實 現,只允許存取記憶體中允許存取的部,這就防止病毒程序使用非法指標存取有成 。也避免指標的操作生的錯CLR 執行中間語言代碼需要對中間語言代碼的安全 性、完性進行驗證防止病毒對中間語言代碼的修改 本支援:系統中的組件或動態聯接庫可能要升級,由於這些組件或動態聯接庫都要在冊表註冊 ,由此可能帶來一系,例如,安新程序時自動安新組件替換舊組件, 有可能使些必須使用組件可以執行的程序,使用新組件執行不了。在.NET 中這些組

第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

  • Upload
    others

  • View
    12

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

1

第一章第一章第一章第一章 C#語言基礎語言基礎語言基礎語言基礎

本章介紹 C#語言的基礎知識,希望具有 C語言的讀者能夠基本掌握 C#語言,以此為基礎,

能夠進一步學習用 C#語言編寫Window應用程序和Web應用程序。當然僅靠一章的內容就完

全掌握 C#語言是不可能的,如需進一步學習 C#語言,還需要認真閱讀有關 C#語言的專著。

1.1 C#語言特點語言特點語言特點語言特點

Microsoft.NET(以下簡稱·NET)框架是微軟提出的新一代 Web 軟件開發模型,C#語言是·NET

框架中新一代的開發工具。C#語言是一種現代、物件導向的語言,它簡化了 C++語言在類、命

名空問、方法多載和異常處理等方面的操作,它摒棄了 C++的複雜性,更易使用,更少出錯。

它使用組件編程,和 VB 一樣容易使用。C#語法和 C++和 JAVA 語法非常相似,如果讀者用過

C++和 JAVA,學習 C#語言應是比較輕鬆的。

用 C#語言編寫的源碼程式,必須用 C#語言編譯器將 C#源碼程式編譯為中間語言(Microsoft

Intermediate Language, MSIL)代碼,形成副檔名為 exe或 dll文件。中間語言代碼不是 CPU可執

行的機器碼,在程序執行時,必須由通用語言執行環境(Common Language Runtime,CLR)中的

即時編譯器(Just In Time,JIT)將中間語言代碼翻譯為 CPU可執行的機器碼,由 CPU執行。CLR

為 C#語言中間語言代碼執行提供了一種執行時環境,C#語言的 CLR 和 JAVA 語言的虛擬機類

似。這種執行方法使執行速度變慢,但帶來其它一些好處,主要有:

� 通用語言規範(Common Language Specification,CLS):.NET系統包括如下語言:C#、C++、

VB、J#,他們都遵守通用語言規範。任何遵守通用語言規範的語言源程序,都可編譯為相

同的中間語言代碼,由 CLR負責執行。只要為其它操作系統編製相應的 CLR,中問語言代

碼也可在其它系統中執行。

� 自動記憶體管理:CLR 內建垃圾收集器,當變數實例的生命周期結束時,垃圾收集器負責

收回不被使用的實例佔用的記憶體空間。不必像 C和 C++語言,用語句在堆積中建立的實

例,必須用語句釋放實例佔用的記憶體空間。也就是說,CLR具有自動記憶體管理功能。

� 跨語言處理:由於任何遵守通用語言規範的語言源程序都可編譯為相同的中間語言代碼,

不同語言設計的組件,可以互相通用,可以從其它語言定義的類衍生出本語言的新類。由

於中間語言代碼由 CLR負責執行,因此異常處理方法是一致的,這在調試一種語言調用另

一種語言的子程序時,顯得特別方便。

� 增加安全:C#語言不支援指標,一切對記憶體的存取者都必須通過物件的參照變數來實

現,只允許存取記憶體中允許存取的部分,這就防止病毒程序使用非法指標存取私有成

員。也避免指標的誤操作產生的錯誤。CLR 執行中間語言代碼需要對中間語言代碼的安全

性、完整性進行驗證,防止病毒對中間語言代碼的修改。

� 版本支援:系統中的組件或動態聯接庫可能要升級,由於這些組件或動態聯接庫都要在註

冊表中註冊,由此可能帶來一系列問題,例如,安裝新程序時自動安裝新組件替換舊組件,

有可能使某些必須使用舊組件才可以執行的程序,使用新組件執行不了。在.NET中這些組

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 2: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

2

件或動態聯接庫不必在註冊表中註冊,每個程序都可以使用自帶的組件或動態聯接庫,只

要把這些組件或動態聯接庫放到執行程序所在文件夾的子文件夾 bin中,執行程序就自動

使用在 bin文件夾中的組件或動態聯接庫。由於不需要在註冊表中註冊,軟件的安裝也變

得容易了,一般將執行程序及庫文件拷貝到指定文件夾中就可以了。

� 完全物件導向:不像 C++語言,暨支援程序導向程序設計,又支援物件導件程序設計,C#

語言是完全物件導向的,在 C#中不再存在全域函數、全域變數,所有的函數、變數和常數

部必須定義在類中,避免了命名衝突。C#語言不支援多重繼承。

1.2編寫主控台應用程序編寫主控台應用程序編寫主控台應用程序編寫主控台應用程序

1.2.1 使用使用使用使用 SDK 命令列工具編寫主控台程序命令列工具編寫主控台程序命令列工具編寫主控台程序命令列工具編寫主控台程序

第一個程式總是非常簡單的,程序首先讓用戶通過鍵盤輸入自己的名字,然後程式在螢幕

上印出一條歡迎訊息,程式碼是這樣的:

using System; //導入命名空間。//為C#語言加註解方法,註解到本行結束 class Welcome //類定義,類的概念見下一節 { /* 註解開始,和C語言註解用法相同 註解結束*/ static void Main() //主程序,程序入口函數,必須在一個類中定義 {

Console.WriteLine("請鍵入你的姓名:"); //主控台輸出字串 Console.ReadLine(); //從鍵盤讀入資料,鍵入Enter結束 Console.WriteLine("歡迎!"); }

}

可以用任意一種文字編輯軟件完成上述程式碼的編寫,然後把文件存檔,假設文件名叫做

welcome.cs,C#源碼檔案是以 cs作為文件的副檔名。和 C語言相同,C#語言是區分大小寫的。

高級語言總是依賴於許多在程式外部預定義的變數和函數。在 C成 C++中這些定義一般放到頭

文件中,用#include語句來導入這個標頭檔,而在 C#語言中使用 using語句導入命名空間,using

System語句意義是導入 System命名空間,C#中的 using語句的用途與 C++中的#include語句的

用途基本類似,用於導入預定義的變數和函數,這樣在自己的程式中就可以自由地使用這些變

數和函數。如果沒有導入命名空間的話,我們該怎麼辦呢?程序還能保持正確嗎?答案是肯定

的,那樣的話,我們就必須把程式碼改寫成下面的樣子:

class Welcome

{

static void Main()

{

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 3: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

3

System.Console.WriteLine("請鍵入你的姓名:"); System.Console.ReadLine();

System.Console.WriteLine("歡迎!"); }

}

也就是在每個 Console前加上一個前綴 System,這個小圓點表示 Console是作為 System的成員

而存在的。C#中拋棄了 C 和 C++中繁雜且極易出錯的運算子,如 :: 和 -> 等,C#中的複合

名字一律通過 · 來連接。System 是 .Net 平台框架提供的最基本的命名空間之一,有關命名

空間的詳細使用方法將在以後詳細介紹,這裡只要學會怎樣導入命名空間就足夠了。

程序的第二行宣告了一個類,類的名字叫做Welcome。C#程序中每個變數或函數都必須屬

於一個類,包括主函數Main(),不能像 C或 C++那樣建立全域變數。C#語言程序總是從Main()

方法開始執行,一個程序中不允許出現兩個或兩行以上的 Main()方法。請牢記 C#中 Main()方

法必須被包含在一個類中,Main的第一個字母必須大寫,必須是一個靜態方法,也就是Main()

方法必須使用 static修飾。static void Main()是類Welcome中定義的主函數,靜態方法意義見以

後章節。

程序所進行的輸入輸出功能是通過 Console 類來完成的,Console 類是在命名空間 System

中已經定義好的一個類。Console有兩個最基本的方法WriteLine和 ReadLine。ReadLine表示從

輸入設備輸入資料,WriteLine則用於在輸出設備上輸出資料。

如果在電腦上安裝了 Visual Studio.Net,則可以在集成開發環境中直接選擇快捷鍵或選單

命令編譯並執行源文件。如果您不具備這個條件,那麼至少需要安裝 Microsoft.Net 這樣才能

夠執行 C#語言程序。Microsoft.Net Framework SDK中內置了 C#的編譯器 csc.exe,下面讓我們

使用這個微軟提供的命令列編譯器時對程序 welcome.cs 進行編譯。假設已經將文件保存在

d:\Csharp目錄下,啟功命令列提示符,在螢幕上輸入一行命令: d: 鍵入 Enter,鍵入命令:

C:\Windows\Microsoft.Net\Framework\v3.5\csc welcome.cs

如果一切正常 welcome.cs文件將被編譯,編譯後產生可執行文件Welcome.exe。可以在命

令提示符視窗執行可執行檔Welcome.exe,螢幕上出現一行文字提示您輸入姓名:請鍵入你的

姓名,輸入任意文字並按下 Enter鍵,螢幕上印出歡迎訊息:歡迎!

注意,和我們使用過的絕大多數編譯器不同,在 C#中編譯器只執行編譯這個過程,而在 C

和 C++中要經過編譯和鏈接兩個階段。換言之 C#源碼檔並不被編譯為目標檔.obj,而是直接產

生成可執行文件.exe或動態鏈接庫.dll,C#編譯器中不需要包含鏈接器。

1.2.1 使用使用使用使用 Visual Studio.Net建立建立建立建立主主主主控台程序控台程序控台程序控台程序

(1) 執行 Visual Studio.Net程序,出現如圖 1.2.2A界面。

(2) 單擊新建專案按鈕,出現如圖 1.2.2B對話框。在專案類型(P)編輯框中選擇 Visual C#,在範

本(T)編輯框中選擇主控制台應用程序,名稱(N)編輯框中鍵入 e1,在位置(L)編輯框中鍵入

D:\Csharp,必須預先產生文件夾 D:\Csharp。也可以單擊瀏覽按鈕,在打開文件對話框中選

擇文件夾,單擊確定按鈕,產生專案。出現如圖 1.2.2C界面。編寫一行應用程序,可能包

Page 4: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

4

含多個文件,才能生成可執行文件,所有這些文件的集合叫做一個專案。

(3) 修改 e1.cs文件如下,有陰影部分是新增加的語句,其餘是集成環境自動生成的。

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace e1

{

class Program

{

static void Main(string[] args)

{

Console.WriteLine("請鍵入你的姓名:");

System.Console.ReadLine();

System.Console.WriteLine("歡迎!");

System.Console.Read();

Page 5: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

5

}

}

}

(4) 按 CTRL+F5 鍵,執行程序,如右圖,與第 1.2.1 節執行效果相同。螢幕上出現一行文字,

提示你輸入姓名,請鍵入你的姓,輸入任意字元並按下 Enter 鍵,螢幕將印出歡迎訊息:

歡迎!鍵入 Enter退出程序。

1.3 類的基本概類的基本概類的基本概類的基本概念念念念

C#語言是一種現代、物件導向的語言,物件導向對程序設計方法提出了一個全新的慨念,·

它的主要思想是將資料(資料成員)及處理這些資料的相應方法(函數成員)封裝到類中,類的實

例則稱為對象或物件(object),這就是我們常說的封裝性。

1.3.1 類的類的類的類的基本概念基本概念基本概念基本概念

類可以認為是對結構的擴充,它和 C中的結構最大的不同是:類中不但可以包括資料,還

包括處理這些資料的函數。類是對資料和處理資料的方法(函數)的封裝。類是對某一類具有相

同特性和行為的事物的描述。例如,定義一個描述個人情況的類 Person如下:

using System;

class Person //類的定義,class是保留字,表示定義一個類,Person是類名 {

private string name = "張三"; //類的資料成員宣告 private int age = 12; //private表示私有資料成員 public void Display() //類的方法(函數)宣告,顯示姓名和年齡 {

Console.WriteLine("姓名:{0},年齡:{1}", name, age); }

public void SetName(string PersonName) //修改姓名為方法(函數) {

name = PersonName;

}

public void setAge(int PersonAge)

{

age = PersonAge;

}

}

Console.WriteLine("姓名:{0},年齡:{1}", name, age)的意義是將第二個參數變數 name變為字

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 6: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

6

串填到{0}位置,將第三個參數變數 age 變為字串填到{1}位置,將第一個參數表示的字串在顯

示器上輸出。

大家注意,這裡我們實際定義了一個新的資料型別,為用戶自己定義的資料型別,是對個

人的特性和行為的描述,型別名為 Person,它和 int、char 等一樣,為一種資料型別。用定義

新資料型別 Person類的方法把資料和處理資料的函數封裝起來。類的宣告格式如下:

屬性 類修飾字 class類名 { 類體 }

其中,關鍵字 class、類名和類體是必須的,其它項是可選項,類修飾字包括 new、public、

protected、internal、private、abstract 和 sealed,這些類修飾字以後介紹,類體用於定義類的

成員。

1.3.2類成員的存取控制類成員的存取控制類成員的存取控制類成員的存取控制

一般希望類中一些資料不被隨意修改,只能按指定方法修改,既隱蔽一些資料,同時這些

函數也不希望被其它類程序調用,只能在類內部使用。如何解決這個問題呢?可用存取權限控

制字,常用的存取權限控制字如下:private(私有)、public(公有)。在資料成員或函數成員前增

加存取權限控制字,可以指定該資料成員或函數成員的存取權限。

私有資料成員只能被類內部的函數使用和修改,私有函數成員只能被類內部的其它函數調

用。類的公有函數成員可以被類的外部程序調用,類的公有資料成員可以被類的外部程序直接

使用修改。公有函數實際是一個類和外部通訊的介面,外部函數通過調用公有函數,按照預先

設定好的方法修改類的私有成員。對於上述例子,name和 age是私有資料成員,只能通過公

有函數 SetName()和 SetAge()修改,即它們只能按指定方法修改。

這裡再一次解釋一下封裝,它有兩個意義,第一是把資料和處理資料的方法同時定義在類

中。第二是用存取權限控制字使資料隱蔽。

1.3.3 類的對象類的對象類的對象類的對象

Person 類僅是一個用戶新定義的資料型別,由它可以生成 Person 類的實例,C#語言叫對

象(或翻譯為物件)。用如下方法宣告類的對象:Person OnePerson=new Person();,此語句的意

義是建立 Person 類對象,返回對象地址指派給 Person 類變數 OnePerson。也可以分兩步產

生 Person類的對象:Person OnePerson;OnePerson = new Person();OnePerson 雖然儲存的是

Person 類對象地址,但不是 C 中的指標,不能像指標那樣可以進行加減運算,也不能轉換為

其它型別地址,它是參照型別變數,只能參照(引用)Person 對象,具體意義參見以後章節。和

C、C++不同,C#只能用此種方法生成類對象。

在程序中,可以用「OnePerson.方法名」或「OnePerson.資料成員名」存取對象的成員。

例如:OnePerson.Display(),公用資料成員也可以這樣存取。注意,C# 語言中不包括 C++語言

中的->符號。

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 7: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

7

1.3.4 類的類的類的類的建構函數建構函數建構函數建構函數和和和和解構解構解構解構函數函數函數函數

在建立類的對象時,需做一些初始化工作,例如對資料成員初始化。這些可以用建構函數

來完成。每當用 new 生成類的對象時,自動調用類的建構函數。因此,可以把初始化的工作

放到建構函數中完成。建構函數和類名相同,沒有返回值。例如可以定義 Person 類的建構函

數如下:

//類的建構函數,函數名和類同名,無返回值。 public Person(string Name, int Age)

{

name = Name;

age = Age;

}

當用 Person OnePerson=new Person("張五",20)語句生成 Person 類對象時,將自動調用

以上建構函數。請注意如何把參數傳遞給建構函數。

變數和類的對象都有生命期,生命期結束,這些變數和對象就要被撤銷。類的對象被撤銷

時,將自動調用解構函數。一些善後工作可放在解構函數中完成。解構函數的名字為「~類名」,

無返回型別,也無參數。Person 類的解構函數為~Person()。C#中類解構函數不能顯式地被調

用,它是被垃圾收集器撤銷不被使用的對象時自動調用的。

1.3.5類的類的類的類的建構函數建構函數建構函數建構函數的的的的多載多載多載多載

在 C#語言中,同一個類中的函數,如果函數名相同,而參數型別或個數不同,認為是不

同的函數,這叫函數多載。僅返回值不同,不能看作不同的函數。這樣,可以在類定義中,定

義多個建構函數,名字相同,參數型別或個數不同。根據生成類的對象方法不同,調用不同的

建構函數。例如可以定義 Person 類沒有參數的建構函數如下:

//類的建構函數,函數名和類同名,無返回型別。 public Person()

{

name = "張三"; age = 12;

}

用語句 Person OnePerson=new Person("李四", 30)生成對象時,將調用有參數的建構函數,

而用語句 Person OnePerson=new Person()生成對象時,調用無參數的建構函數。由於解構函數

無參數,因此,解構函數不能多載。

Administrator
鉛筆
Administrator
鉛筆
Page 8: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

8

1.3.6 使用使用使用使用 Person類的完整的例子類的完整的例子類的完整的例子類的完整的例子

下邊用一個完整的例子說明 Person 類的使用:(VisualStudio.Net 編譯通過)

using System;

namespace e1 //定義以下程式碼所屬命名空間,意義見以後章節 {

class Person

{

private String name = "張三";//類的資料成員宣告 private int age = 12;

//類的方法(函數)宣告,顯示姓名和年齡 public void Display()

{

Console.WriteLine("姓名: {0}, 年齡:{1}", name, age); }

//指定修改姓名的方法(函數) public void SetName(string PersonName)

{

name = PersonName;

}

//指定修改年齡的方法(函數) public void SetAge(int PersonAge)

{

age = PersonAge;

}

//建構函數,函數名和類同名,無返回值 public Person(string Name, int Age)

{

name = Name;

age = Age;

}

//類的建構函數多載 public Person()

{

name = "田七"; age = 12;

}

Page 9: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

9

class Class1

{

static void Main(string[] args)

{

Person OnePerson = new Person("李四", 30); //生成類的對象 OnePerson.Display();

/*下句錯誤,在其它類(Class1類)中, 不能直接修改Person類中的私有成員。*/ //OnePerson.name = "王五"; /* 只能通過Person類中公有方法SetName 修改Person類中的私有成員name。*/ OnePerson.SetName("王五"); OnePerson.SetAge(40);

OnePerson.Display();

OnePerson = new Person();

OnePerson.Display();

}

}

}

}

鍵入 CTRL+F5執行後,顯示的效果是:

姓名: 李四, 年齡:30

姓名: 王五, 年齡:40

姓名: 田七, 年齡:12

1.4 C#的的的的資料資料資料資料型別型別型別型別

從大的方面來分,C# 語言的資料型別可以分為三種:實值型別、參照型別、指標(pointer)

型別,指標型別僅用於非安全程式碼中。本節重點討論實值型別和參照型別。

1.4.1 實值型別實值型別實值型別實值型別和和和和參照參照參照參照型別型別型別型別區別區別區別區別

在 C# 語言中,實值型別變數儲存的是資料型別所代表的實際資料,實值型別變數的值(或

實例)儲存在堆疊(Stack)中,指派語句是傳遞變數的值。參照型別(例如類就是參照型別)的實

例,也稱為對象,不存在堆疊中,而儲存在受管的堆積(Managed Heap)中,堆積實際上是計算

機系統中的空閒記憶體。參照型別變數的值儲存在堆疊中,但儲存的不是參照型別對象,而是

儲存參照型別對象的參照(地址),和指標所代表的地址不同,參照所代表的地址不能被修改,

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 10: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

10

也不能轉換為其它型別地址,它是參照型別變數,只能參照指定類對象,參照型別變數指派語

句是傳遞對象的地址。見下例:

using System;

class MyClass//類為參照型別 {

public int a = 0;

}

class Test

{

static void Main()

{

f1();

}

static public void f1()

{

int v1 = 1;//實值型別變數v1,其值儲存在堆疊(Stack)中 int v2 = v1;//將v1的值(為)傳遞給v2,v2 = 1,v1值不變。 v2 = 2;//v2 = 2,v1 值不變。 MyClass r1 = new MyClass();//參照變數r1儲存MyClass類對象的地址 MyClass r2 = r1;//r1和r2都代表是同一個MyClass類對象 r2.a = 2;//和語句r1.a = 2 等價 }

}

儲存在堆疊中的變數,當其生命期結束,自動被撤銷,例如,v1 儲存在堆疊中,v1 和函

數 f1 同生命期,退出函數 f1,此時 v1不存在了。但在堆積中的對象不能自動被撤銷。因此 C

和 C++語言,在堆積中建立的對象,不使用時必須用語句釋放對象佔用的儲存空間。.NET 系

統 CLR 內建垃圾收集器,當對象的參照變數被撤銷,表示對象的生命期結束,垃圾收集器負

責收回不被使用的對象佔用的儲存空間。例如,上例中參照變數 r1 及 r2 是 MyClass類對象

的參照,儲存在堆疊中,退出函數 f1,此時 r1 和 r2 都不存在了,在堆積中的 MyClass 類對

象也就被垃圾收集器撤銷。也就是說,CLR 具有自動記憶體管理功能。

1.4.2實值型別實值型別實值型別實值型別變數變數變數變數分類分類分類分類

C#語言實值型別可以分為以下幾種:

� 簡單型別(Simple types)

簡單型別中包括:數值型別和布爾型別(bool)。數值型別又細分為:整數型別、字元型別

(char)、浮點數型別和十進制型別(decimal)。

� 結構型別(Struct types)

Administrator
鉛筆
Administrator
鉛筆
Page 11: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

11

� 列舉型別(Enumeration types)

C#語言實值型別變數無論如何定義,總是實值型別變數,不會變為參照型別變數。

1.4.3 結構結構結構結構型別型別型別型別

結構型別和類一樣,可以宣告建構函數、資料成員、方法、屬性等。結構和類的最根本的

區別是結構是實值型別,類是參照型別。和類不同,結構不能從另外一個結構或者類衍生,本

身也不能被繼承,因此不能定義抽像結構,結構成員也不能被存取權限控制字 protected 修飾,

也不能用 virtual 和 abstract 修飾結構方法。在結構中不能定義解構函數。但結構有預設的無

參數建構函數。

雖然結構不能從類和結構衍生,可是結構能夠繼承介面,結構繼承介面的方法和類繼承介

面的方法基本一致。下面例子定義一個點結構 point:

using System;

struct point//結構定義 {

public int x, y;//結構中也可以宣告建構函數(必須有參數)和方法,變數不能賦初值 }

class Test

{

static void Main()

{

point P1;

P1.x = 166;

P1.y = 111;

point P2;

P2 = P1;//值傳遞,使P2.x = 166,P2.y = 111 point P3 = new point();//用new 生成結構變數P3,P3 仍為實值型別變數 } //用new 生成結構變數P3 僅表示調用預設的建構函數,使x=y=0。 }

1.4.4簡單簡單簡單簡單型別型別型別型別

簡單型別也是結構型別,因此有建構函數、資料成員、方法、屬性等,因此下列語句 int i

= int.MaxValue; string s = i.ToString()是正確的。即使一個常數,C#也會生成結構型別的實例,因

此也可以使用結構型別的方法,例如:string s = 13.ToString()是正確的。簡單型別包括:整數型

別、字元型別、布爾型別、浮點數型別、十進制型別。見下表:

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 12: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

12

保留字 System 命名空

間中的名字

位元

組數 取值範圍 範例

sbyte System.Sbyte 1 –128~127

byte System.Byte 1 0~255

short System.Int16 2 –32768~32767

ushort System.UInt16 2 0~65535

int System.Int32 4 –2147483648~2147483647

uint System.UInt32 4 0~4292967295

long System.Int64 8 –9223372036854775808 long x = 36L;

ulong System.UInt64 8 0~18446744073709551615 ulong x = 36UL;

char System.Char 2 0~65535 char x = '中';

float System.Single 4 3.4E-38~3.4E+38 float x = 23.56F;

double System.Double 8 1.7E-308~1.7E+308 double x = 23.56D;

bool System.Boolean 1 (true, false) bool x = true, y = false;

decimal System.Decimal 16 正負 1.0×10−28到 7.9×10

28之間 decimal x = 1.68M;

C#簡單型別使用方法和 C、C++中相應的資料型別基本一致。需要注意的是:

� 和 C 語言不同,無論在何種系統中,C# 每種資料型別所佔位元組(byte)數是固定的。

� 字元型別採用 Unicode 字元集,一個 Unicode 標準字元長度為 16 位。

� 整數型別不能被隱式轉換為字元型別(char),例如 char c1 = 10 是錯誤的,必須寫成:char

c1 = (char)10、char c = 'A'、char c = '\x0032'、char c = '\u0032'。

� 布爾型別有兩個值:false,true。不能認為整數 0 是 false,其它值是 true。bool x = 1是錯

誤的,不存在這種寫法,只能寫成 x = true 或 x = false。

� 十進制型別(decimal)也是浮點數型別,只是精度比較高,一般用於財政金融計算。

1.4.5 列舉列舉列舉列舉型別型別型別型別

C#列舉型別使用方法和 C、C++中的列舉型別基本一致。見下例:

using System;

class Class1

{

enum Days { Sat, Sun, Mon, Tue, Wed, Thu, Fri };

//使用Visual Studio.Net,enum語句添加在[STAThread]前邊 static void Main(string[] args)

{

Days day = Days.Tue;

int x = (int)Days.Tue;//x=2

Console.WriteLine("day={0}, x={1}", day, x);

Page 13: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

13

//顯示結果為:day=Tue, x=3 }

}

在此列舉型別 Days 中,每個元素的預設的型別為 int,其中 Sat=0,Sun=1,Mon=2,

Tue=3,依此類推。也可以直接給列舉元素指派值。例如:

enum Days{Sat=1,Sun,Mon,Tue,Wed,Thu,Fri,Sat};

在此列舉中,Sat=1,Sun=2,Mon=3,Tue=4,Wed=5,等等。和 C、C++中不同,C#列舉

元素型別可以是 byte、sbyte 、short、ushort、int、uint、long 和 ulong 型別,但不能是 char

型別。見下例:

enum Days:byte{Sun,Mon,Tue,Wed,Thu,Fri,Sat};//元素為 byte型別

1.4.6實值型別實值型別實值型別實值型別的初值和的初值和的初值和的初值和預設的預設的預設的預設的建構函數建構函數建構函數建構函數

所有變數都要求必須有初值,如沒有指派值,採用預設值。對於簡單型別,sbyte、byte、

short、ushort、int、uint、long 和 ulong 預設值為 0,char 型別預設值是(char)0,float為 0.0f,

double 為 0.0d,decimal 為 0.0m,bool 為 false,列舉型別為 0,在結構型別和類中,資料

成員的實值型別變數設置為預設值,參照型別變數設置為 null。

可以顯式的指派值,例如 int i = 0。而對於複雜結構型別,其中的每個資料成員都按此種

方法指派值,顯得過於麻煩。由於實值型別都是結構型別,可用 new 語句調用其建構函數初

始化實值型別變數,例如:int j = new int()。請注意,用 new 語句並不是把 int 變數變為參照

變數,j 仍是實值型別變數,這裡 new 僅僅是調用其建構函數。所有的實值型別都有預設的

的無參數的建構函數,其功能就是為該實值型別賦初值為預設值。對於自定義結構型別,由於

已有預設的的無參數的建構函數,不能再定義無參數的建構函數,但可以定義有參數的建構函

數。

1.4.7 參照參照參照參照型別型別型別型別分類分類分類分類

C#語言中參照型別可以分為以下幾種:

� 類:C#語言中預定義了一些類:對象類(object 類)、陣列類、字串類等。當然,程式設計

師可以定義其它類。

� 介面。

� 委派。

C#語言參照型別變數無論如何定義,總是參照型別變數,不會變為實值型別變數。C# 語

言參照型別對象一般用運算子 new 建立,用參照型別變數引用該對象。本節僅介紹對象型別

(object型別)、字串型別、陣列。其它型別在其它節中介紹。

Administrator
鉛筆
Administrator
鉛筆
Page 14: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

14

1.4.8 對象對象對象對象類類類類(object class)

C#中的所有型別(包括數值型別)都直接或間接地以 object類為基類。對象類(object類)是所

有其它類的基類。任何一個類定義,如果不指定基類,預設 object為基類。繼承和基類的概念

見以後章節。C#語言規定,基類的參照變數可以引用衍生類的對象(注意,衍生類的參照變數

不可以引用基類的對象),因此,對一個 object的變數可以賦予任何型別的值:

int x = 25;

object obj1;

obj1 = x;

object obj2 = 'A';

object 關鍵字是在命名空間 System 中定義的,是類 System.Object 的別名。

1.4.9陣列陣列陣列陣列類類類類

在進行批次處理資料的時候,要用到陣列。陣列是一組型別相同的有序資料。陣列按照陣

列名、資料元素的型別和維數來進行描述。C#語言中陣列是類 System.Array類對象,比如宣告

一個整數型陣列:int[] arr = new int[5];,實際上產生了一個陣列類對象,arr是這個對象的參照

(地址)。

在 C#中陣列可以是一維的,也可以是多維的,同樣也支援陣列的陣列,即陣列的元素還

是陣列。一維陣列最為普遍,用的也最多。我們先看一個一維陣列的例子:

using System;

class Test

{

static void Main()

{

int[] arr = new int[3];//用new運算子建立一個個元素的一維陣列 for (int i = 0; i < arr.Length; i++)/* arr.Length是陣列類變數, 表示陣列元素個數*/ arr[i] = i * i;//陣列元素指派初值,arr[i]表示第i個元素的值 for (int i = 0; i < arr.Length; i++)//陣列第一個元素的下標為 Console.WriteLine("arr[{0}] = {1}", i, arr[i]);

}

}

這段程式碼產生了一個 int型別 3個元素的一維陣列,初始化後逐項輸出。其中 arr.Length

表示陣列元素的個數。注意陣列定義不能寫為 C語言格式:int arr[]。程序的輸出為:

arr[0] = 0

arr[1] = 1

Page 15: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

15

arr[2] = 4

上面的例子中使用的是一維陣列,下面介紹多維陣列:

string[] a1;//一維 string陣列類參照變數 a1

string[,] a2;//二維 string陣列類參照變數 a2

a2 = new string[2,3];

a2[1,2] = "abc";

string[,,] a3;//三維 string陣列類參照變數 a3

string[][] j2;//陣列的陣列,即陣列的元素還是陣列

string[][][][] j3;

在陣列宣告的時候,可以對陣列元素進行指派值。看下面的例子:

int[] a1 = new int[]{1,2,3};//一維陣列,有 3個元素。

int[] a2 = new int[3]{1,2,3};//此格式也正確

int[] a3 = {1,2,3};//相當於 int[] a3=new int[]{1,2,3};

int[,] a4 = new int[,]{{1,2,3},{4,5,6}};//二維陣列,a4[1,1]=5

int[][] j2 = new int[3][];//定義陣列 j2,有三個元素,每個元素都是一個陣列

j2[0] = new int[]{1,2,3};//定義第一個元素,是一個陣列

j2[1] = new int[]{1, 2, 3, 4, 5, 6};//每個元素的陣列可以不等長

j2[2] = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};

1.4.10字串字串字串字串類類類類(string類類類類)

C#還定義了一個基本的類 string,專門用於對字串的操作。這個類也是在命名空間 System

中定義的,是類 System.String 的別名。字串應用非常廣泛,在 string 類的定義中封裝了許多

方法,下面的一些語句展示了 string 類的一些典型用法:

� 字串定義

string s;//定義一個字串參照型別變數 s

s = "Zhang";//字串參照型別變數 s 指向字串"Zhang"

string FirstName = "Ming";

string LastName = "Zhang";

string Name = FirstName+" "+LastName;//運算子+已被多載

string SameName = Name;

char[] s2 = {'計','算','機','科','學'};

string s3 = new String(s2);

� 字串搜索

string s = "ABC科學";

int i = s.IndexOf("科");

搜索"科"在字串中的位置,因第一個字元索引為 0,所以"A"索引為 0,"科"索引為 3,因

此這裡 i = 3,如沒有此字串 i = –1。注意 C#中,ASCII和漢字都用 2個位元組表示。

Page 16: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

16

� 字串比較函數

string s1 = "abc";

string s2 = "abc";

int n = string.Compare(s1,s2);//n = 0

n 值得到 0表示兩個字串相同,n值小於零,表示 s1 < s2,n值大於零,表示 s1 > s2。此

方法區分大小寫。也可用如下辦法比較字串:

string s1 = "abc";

string s = "abc";

string s2 = "不相同";

if(s == s1)//還可用!=。雖然 String是參照型別,但此寫法仍可比較兩個字串的值

s2 = "相同";

� 判斷是否為空字串

string s = "";

string s1 = "不空";

if(s.Length == 0)

s1 = "空";

� 得到子字串或字元

string s = "取子字串";

string sb = s.Substring(2,2);//從索引為 2開始取 2個字元,Sb="字串",s內容不變

char sb1 = s[0];//sb1='取'

Console.WriteLine(sb1);//顯示:取

� 字串刪除函數

string s = "取子字串";

string sb = s.Remove(0,2);//從索引為 0開始刪除 2個字元,Sb="字串",s內容不變

� 插入字串

string s = "計算機科學";

string s1 = s.Insert(3, "軟件");//s1="計算機軟件科學",s內容不變

� 字串替換函數

string s = "計算機科學";

string s1 = s.Replace("計算機","軟件");//s1="軟件科學",s內容不變

� 把 string 轉換為字元陣列

string s = "計算機科學";

char[] s2 = s.ToCharArray(0, S.Length);//屬性 Length為字串類對象的長度

� 其它資料型別轉換為字串

int i = 9;

string s8 = i.ToString();//s8="9"

float n = 1.9f;

string s9 = n.ToString();//s8="1.9"

Page 17: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

17

其它資料型別都可用此方法轉換為字串類對象

� 大小寫轉換

string s = "AaBbCc";

string s1 = s.ToLower();//把字元轉換為小寫,s 內容不變

string s2 = s.ToUpper();//把字元轉換為大寫,s 內容不變

� 刪除所有的空格

string s = "A bc ";

s.Trim();//刪除所有的空格

string 類其它方法的使用請用幫助系統查看,方法是打開 Visual Studio.Net 的程式碼編輯

器,鍵入 string,將游標移到鍵入的字串 string 上,然後按 F1 鍵。

1.4.11 型別型別型別型別轉換轉換轉換轉換

在編寫 C# 語言程式時,經常會碰到型別轉換問題。例如整數和浮點數相加,C#會進行隱

式轉換。詳細記住那些型別資料可以轉換為其它型別資料,是不可能的,也是不必要的。程式

設計師應記住型別轉換的一些基本原則,編譯器在轉換發生問題時,會給提示。C# 語言中型

別轉換分為:隱式轉換、顯示轉換、裝箱(boxing)和拆箱(unboxing)等三種。

一、隱式轉換

隱式轉換就是系統預設的的、不需要加以宣告就可以進行的轉換。例如從 int型別轉換到

long型別就是一種隱式轉換。在隱式轉換過程中,轉換一般不會失敗,轉換過程中也不會導致

訊息丟失。例如:

int i = 10;

long l = i;

二、顯示轉換

顯式型別轉換,又叫強制型別轉換。與隱式轉換正好相反,顯式轉換需要明確地指定轉換

型別,顯示轉換可能導致訊息丟失。下面的例子把長整數型變數顯式轉換為整數型:

long l = 5000;

int i = (int)l;//如果超過 int取值範圍,將產生異常

三、裝箱(boxing)和拆箱(unboxing)

裝箱(boxing)和拆箱(unboxing)是 C#語言型別系統提出的核心概念,裝箱是實值型別轉換為

object(對象)型別,拆箱是 object(對象)型別轉換為實值型別。有了裝箱和拆箱的概念,對任何

型別的變數來說,最終我們都可以看作是 object型別。

1. 裝箱操作

把一個實值型別變數裝箱也就是產生一個 object對象,並將這個實值型別變數的值複製給

這個 object對象。例如:

int i = 10;

object obj = i;//隱式裝箱操作,obj為產生的 object對象的參照。

我們也可以用顯式的方法來進行裝箱操作,例如:

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 18: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

18

int i =10;

object obj = object(i);//顯式裝箱操作

實值型別的值裝箱後,實值型別變數的值不變,僅將這個實值型別變數的值複製給這個

object對象。我們看一下下面的程式:

using System

class Test

{

public static void Main()

{

int n = 200;

object o = n;

o = 201;//不能改變 n

Console.WriteLine("{0}, {1}", n, o);

}

}

輸出結果為:200, 201。這就證明了實值型別變數 n和 object類對象 o都獨立存在著。

2. 拆箱操作

和裝箱操作正好相反,拆箱操作是指將一個對象型別顯式地轉換成一個實值型別。拆箱的

過程分為兩步:首先檢查這個 object對象,看它是否為給定的實值型別的裝箱值,然後,把這

個對象的值複製給實值型別的變數。我們舉個例子來看看一個對象拆箱的過程:

int i = 10;

object obj = i;

int j = (int)obj;//拆箱操作

可以看出拆箱過程正好是裝箱過程的逆過程,必須注意裝箱操作和拆箱操作必須遵循型別

兼容的原則。

3. 裝箱和拆箱的使用

定義如下函數:

void Display(Object o)//注意,o為 Object型別

{

int x=(int)o;//拆箱

System.Console.WriteLine("{0},{1}",x,o);

}

調用此函數:int y = 20; Display(y);在此利用了裝箱概念,形參被實參替換:Object o = y,

也就是說,函數的參數是 Object型別,可以將任意型別實參傳遞給函數。

1.5運算運算運算運算子子子子

C#語言和 C 語言的運算子用法基本一致。以下重點講解二者之間不一致部分。

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 19: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

19

1.5.1運算運算運算運算子子子子分類分類分類分類

與 C語言一樣,如果按照運算子所作用的運算元個數來分,C#語言的運算子可以分為以下

幾種類型:

� 一元運算子:一元運算子作用於一個運算元,例如:–x、++x、x--等。

� 二元運算子:二元運算子對兩個運算元進行運算,例如:x+y。

� 三元運算子:三元運算子只有一個:x? y:z。

C#語言運算子的詳細分類及運算子從高到低的優先級順序見下表。

分類 運算子 結合性

初級 (x) x.y f(x) a[x] x++ x–– new typeof sizeof checked unchecked 左

單元 + – ! ~ ++x ––x (T)x 左

乘法等 * / % 左

加法等 + – 左

移位 << >> 左

關係 < > <= >= is as 左

相等 == != 右

邏輯與 & 左

邏輯異或 ^ 左

邏輯或 | 左

條件與 && 左

條件或 || 左

條件 ?: 右

指派等 = *= /= %= += –= <<= >>= &= ^= |= 右

1.5.2 測試測試測試測試運算子運算子運算子運算子 is

is運算子用於動態地檢查表達式是否為指定型別。使用格式為:e is T,其中 e是一個表達

式,T是一個型別,該式判斷 e是否為 T型別,返回值是一個布爾值。例子:

using System;

class Test

{

public static void Main()

{

Console.WriteLine(1 is int);

Console.WriteLine(1 is float);

Console.WriteLine(1.0f is float);

Page 20: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

20

Console.WriteLine(1.0d is double);

}

}

輸出為:

True

False

True

True

1.5.3 typeof運算子運算子運算子運算子

typeof運算子用於獲得指定型別在 System命名空間中定義的型別名字,例如:

using System;

class Test

{

static void Main()

{

Console.WriteLine(typeof(int));

Console.WriteLine(typeof(System.Int32));

Console.WriteLine(typeof(string));

Console.WriteLine(typeof(double[]));

}

}

產生如下輸出,由輸出可知 int和 System.int32是同一型別。

System.Int32

System.Int32

System.String

System.Double[]

1.5.4 溢出檢查溢出檢查溢出檢查溢出檢查運算子運算子運算子運算子 checked 和和和和 unchecked

在進行整數型算術運算(如+、-、*、/等)或從一種整數型顯式轉換到另一種整數型時,有

可能出現運算結果超出這個結果所屬型別值域的情況,這種情況稱之為溢出。整數型算術運算

表達式可以用 checked或 unchecked溢出檢查運算子,決定在編譯和執行時是否對表達式溢出

進行檢查。如果表達式不使用溢出檢查運算子或使用了 checked運算子,常數表達式溢出,在

編譯時將產生錯誤,表達式中包含變數,程序執行時執行該表達式產生溢出,將產生異常提示

訊息。而使用了 unchecked運算子的表達式語句,即使表達式產生溢出,編譯和執行時都不會

產生錯誤提示。但這往往會出現一些不可預期的結果,所以使用 unchecked運算子要小心。

Page 21: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

21

下面的例子說明了 checked和 unchecked運算子的用法:

using System;

class Class1

{

static void Main(string[] args)

{

const int x = int.MaxValue;

unchecked//不檢查溢出

{

int z = x*2;//編譯時不產生編譯錯誤,z = –2

Console.WriteLine("z={0}", z);//顯示–2

}

checked//檢查溢出

{

int z1 = (x*2);//編譯時會產生編譯錯誤

Console.WriteLine("z = {0}", z1);

}

}

}

1.5.5 new運算子運算子運算子運算子

new運算子可以產生實值型別變數、參照型別對象,同時自動調用建構函數。例如:

int x = new int();//用 new產生整數型變數 x,調用預設的建構函數

Person C1 = new Person ();//用 new建立的 Person類對象。

// Person型別變數 C1是對象的參照

int[] arr=new int[2];//陣列也是類,產生陣列類對象,arr是陣列對象的參照

需注意的是,int x = new int()語句將自動調用 int結構不帶參數的建構函數,給 x賦初值 0,

x仍是實值型別變數,不會變為參照型別變數。

1.5.6 運算子運算子運算子運算子的優先級的優先級的優先級的優先級

當一個表達式包含多種運算子時,運算子的優先級控制著運算子求值的順序。例如,表達

式 x+y*z按照 x+(y*z)順序求值,因為*運算子比+運算子有更高的優先級。這和數學運算中的先

乘除後加減是一致的。1.5.1節中的表總結了所有運算子從高到低的優先級順序。

當兩個有相同優先級的運算子對運算元進行運算時,例如 x+y–z,運算子按照出現的順序

由左至右執行,x+y–z按(x+y)–z進行求值。指派運算子按照右接合的原則,即操作按照從右向

左的順序執行。如 x=y=z按照 x=(y=z)進行求值。建議在寫表達式的時候,如果無法確定運算子

Page 22: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

22

的實際順序,則盡量採用括號來保證運算的順序,這樣也使得程式一目瞭然,而且自己在編程

時能夠思路清晰。

1.6程序控制語句程序控制語句程序控制語句程序控制語句

C#語言控制語句和 C基本相同,使用方法基本一致。C#語言控制語句包括:if 語句、swith

語句、while 語句、do…while 語句、for語句、foreach語句、break 語句、continue語句、goto

語句、return 語句、異常處理語句等,其中 foreach 語句和異常語句是 C# 語言新增加控制語

句。

本節首先介紹一下這些語句和 C語言的不同點,然後介紹 C# 語言新增的控制語句。

1.6.1 和和和和 C 語言的不同點語言的不同點語言的不同點語言的不同點

� 與 C不同,if語句、while 語句、do…while 語句、for語句中的判斷語句,一定要用布爾

表達式,不能認為 0為 false,其它數為 true。

� switch語句不再支援遍歷,C和 C++語言允許 switch語句中 case標籤後不出現 break語句,

但 C#不允許這樣,它要求每個 case標籤項後使用 break語句或 goto跳轉語句,即不允許

從一個 case 自動遍歷到其它 case,否則編譯時將報錯。switch 語句的控制型別,即其中控

制表達式的資料型別可以是 sbyte、byte、short、ushort、uint、long、ulong、char、string

或列舉型別。每個 case 標籤中的常數表達式必須屬於或能隱式轉換成控制型別。如果有

兩個或兩個以上 case 標籤中的常數表達式值相同,編譯時將會報錯。執行 switch 語句,

首先計算 switch 表達式,然後與 case 後的常數表達式的值進行比較,執行第一個與之匹

配的 case分支下的語句。如果沒有 case常數表達式的值與之匹配,則執行 default分支下

的語句,如果沒有 default語句,則退出 switch語句。switch語句中可以沒有 default語句,

但最多只能有一個 default語句。見下例:

using System;

class class1

{

static void Main()

{

System.Console.WriteLine("請輸入要計算天數的月份");

string s = System.Console.ReadLine();

string s1 = "";

switch(s)

{

case "1": case "3": case "5":

case "7": case "8": case "10":

case "12"://共用一條語句

Administrator
鉛筆
Administrator
鉛筆
Page 23: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

23

s1 = "31"; break;

case "2":

s1 = "28"; break;

case "4": case "6": case "9":

goto case "11";//goto語句僅為說明問題,無此必要

case "11":

s1 = "30"; break;

default:

s1 = "輸入錯誤"; break;

}

System.Console.WriteLine(s1);

}

}

1.6.2 foreach 語句語句語句語句

foreach語句是 C#語言新引入的語句,C和 C++中沒有這個語句,它借用 Visual Basic中的

foreach語句。語句的格式為:

foreach(型別 變數名 in 表達式) 循環語句

其中表達式必須是一個陣列或其它集合型別,每一次循環從陣列或其它集合中逐一取出資料,

指派給指定型別的變數,該變數可以在循環語句中使用、處理,但不允許修改變數,該變數的

指定型別必須和表達式所代表的陣列或其它集合中的資料型別一致。例子:

using System;

class Test()

{

public static void Main()

{

int[] list = {10, 20, 30, 40};//陣列

foreach(int m in list)

Console.WriteLine("{0}", m);

}

}

對於一維陣列,foreach 語句循環順序是從下標為 0 的元素開始一直到陣列的最後一個元

素。對於多維陣列,元素下標的遞增是從最右邊那一維開始的。同樣 break和 continue可以出

現在 foreach語句中,功能不變。

Administrator
鉛筆
Page 24: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

24

1.6.3異常語句異常語句異常語句異常語句

在編寫程序時,不僅要關心程序的正常操作,還應該考慮到程序執行時可能發生的各類不

可預期的事件,比如用戶輸入錯誤、記憶體不夠、磁碟出錯、網路資源不可用、資料庫無法使

用等,所有這些錯誤被稱作異常或例外(exception),不能因為這些異常使程序執行產生問題。

各種程序設計語言經常採用異常處理語句來解決這類異常問題。

C#提供了一種處理系統級錯誤和應用程序級錯誤的結構化的、統一的、型別安全的方法。

C#異常語句包含 try子句、catch子句和 finally子句。try子句中包含可能產生異常的語句,該

子句自動捕捉執行這些語句過程中發生的異常。catch 子句中包含了對不同異常的處理程式

碼,可以包含多個 catch 子句,每個 catch 子句中包含了一個異常型別,這個異常型別必須是

System.Exception 類或它的衍生類參照變數,該語句只捕捉該型別的異常。可以有一個通用異

常型別的 catch 子句,該 catch 子句一般在事先不能確定會發生什麼樣的異常的情況下使用,

也就是可以捕捉任意型別的異常。一個異常語句中只能有一個通用異常型別的 catch子句,而

且如果有的話,該 catch子句必須排在其它 catch子句的後面。無論是否產生異常,子句 finally

一定被執行,在 finally子句中可以增加一些必須執行的語句。

異常語句捕捉和處理異常的機理是:當 try 子句中的程式碼產生異常時,按照 catch 子句

的順序查找異常型別。如果找到,執行該 catch子句中的異常處理語句。如果沒有找到,執行

通用異常型別的 catch 子句中的異常處理語句。由於異常的處理是按照 catch 子句出現的順序

逐一檢查 catch 子句,因此 catch 子句出現的順序是很重要的。無論是否產生異常,一定執行

finally子句中的語句。異常語句中不必一定包含所有三個子句,因此異常語句可以有以下三種

可能的形式:

� try-catch語句,可以有多個 catch語句

� try-finally語句

� try-catch-finally語句,可以有多個 catch語句

請看下邊的例子:

1. try-catch-finally語句

using System

using System.IO//使用文件必須引用的命名空間

public class Example

{

public static void Main()

{

StreamReader sr = null;//必須賦予初值 null,否則編譯不能通過

try

{

sr = File.OpenText("d:\\csarp\\test.txt");//可能產生異常

string s;

Administrator
鉛筆
Page 25: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

25

while(sr.Peek() != –1)

{

s = sr.ReadLine();//可能產生異常

}

Console.WriteLine(s);

}

catch(DirectoryNotFoundException e)//無指定目錄異常

{

Console.WriteLine(e.Message);

}

catch(FileNotFoundException e)//無指定文件異常

{

Console.WriteLine("文件"+e.FileName+"未被發現");

}

catch(Exception e)//其它所有異常

{

Console.WriteLine("處理失敗:{0}",e.Message);

}

finally

{

if(sr != null) sr.Close();

}

}

}

2. try-finally語句

上例中,其實可以不用 catch語句,在 finally子句中把文件關閉,提示用戶是否正確打開

了文件,請讀者自己完成。

3. try-catch語句

請讀者把上例修改為使用 try-catch結構,注意在每個 catch語句中都要關閉文件。

1.7類的繼承類的繼承類的繼承類的繼承

在 1.3節,定義了一個描述個人情況的類 Person,如果我們需要定義一個僱員類,當然可

以從頭開始定義僱員類 Employee。但這樣不能利用 Person類中已定義的函數和資料。比較好

的方法是,以 Person類為基礎(基類),衍生出一個僱員類 Employee,僱員類 Employee繼承了

Person 類的資料成員和函數成員,既 Person 類的資料成員和函數成員成為 Employee 類的成

員。這個 Employee類稱為以 Person類為基類的衍生類,這是 C#給我們提出的方法。C#用繼承

的方法,實現程式碼的重用。

Page 26: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

26

1.7.1 衍生衍生衍生衍生類的類的類的類的宣告宣告宣告宣告格式格式格式格式

衍生類的宣告格式如下:

屬性 類修飾符 class 衍生類名 : 基類名 { 類體 }

僱員類 Employee定義如下:

class Employee : Person//Person類是基類

{

private string department;//部門,新增資料成員

private decimal salary;//工資,新增資料成員

public Employee(string Name,int Age,string D,decimal S) : base(Name,Age)

{

/*注意 base的第一種用法,根據參數調用指定基類建構函數, 注意參數的傳遞 */

department = D;

salary = S;

public new void Display()//覆蓋基類 Display()方法,

//注意用 new,本例不可用 override

{

base.Display();//存取基類被覆蓋的方法,base的第二種用法

Console.WriteLine("部門:{0} 工資:{1}",department,salary);

}

}

}

修改主函數如下:

class Class1

{

static void Main(string[] args)

{

Employee OneEmployee = new Employee("李四",30,"計算機系",2000);

OneEmployee.Display();

}

}

Employee 類繼承了基類 Person 的方法 SetName()、SetAge(),資料成員 name 和 age,即

認為基類 Person的這些成員也是 Employee類的成員,但不能繼承建構函數和解構函數。添加

了新的資料成員 department 和 salary。覆蓋了方法 Display()。請注意,雖然 Employee 類繼承

了基類 Person的 name和 age,但由於它們是基類的私有成員,Employee類中新增或覆蓋的方

法不能直接修改 name和 age,只能通過基類原有的公有方法 SetName()和 SetAge()修改。如果

Page 27: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

27

希望在 Employee類中能直接修改 name和 age,必須在基類中修改它們的屬性為 protected。

1.7.2 base 關鍵字關鍵字關鍵字關鍵字

base關鍵字用於從衍生類中存取基類成員,它有兩種基本用法:

� 在定義衍生類的建構函數中,指明要調用的基類建構函數,由於基類可能有多個建構函

數,根據 base 後的參數型別和個數,指明要調用哪一個基類建構函數。參見上節僱員類

Employee建構函數定義中的 base的第一種用法。

� 在衍生類的方法中調用基類中被衍生類覆蓋的方法。參見上節僱員類 Employee的 Display()

方法定義中的 base的第二種用法。

1.7.3 覆蓋基類成員覆蓋基類成員覆蓋基類成員覆蓋基類成員

在衍生類中,通過宣告與基類完全相同新成員,可以覆蓋基類的同名成員,完全相同是指

函數型別、函數名、參數型別和個數都相同。如上例中的方法 Display()。衍生類覆蓋基類成員

不算錯誤,但會導致編譯器發出警告。如果增加 new 修飾符,表示認可覆蓋,編譯器不再發

出警告。請注意,覆蓋基類的同名成員,並不是移走基類成員,只是必須用如下格式存取基類

中被衍生類覆蓋的方法:base.Display()。

1.7.4 C#語言類繼承特點語言類繼承特點語言類繼承特點語言類繼承特點

C#語言類繼承有如下特點:

� C#語言只允許單繼承,即衍生類只能有一個基類。

� C#語言繼承是可以傳遞的,如果 C從 B衍生,B從 A衍生,那麼 C不但繼承 B的成員,還

要繼承 A中的成員。

� 衍生類可以添加新成員,但不能刪除基類中的成員。

� 衍生類不能繼承基類的建構函數、解構函數和事件。但能繼承基類的屬性。

� 衍生類可以覆蓋基類的同名成員,如果在衍生類中覆蓋了基類同名成員,基類該成員在衍

生類中就不能被直接存取,只能通過「base.基類方法名」存取。

� 衍生類對象也是其基類的對象,但基類對象卻不是其衍生類的對象。例如,前面定義的僱

員類 Employee 是 Person 類的衍生類,所有僱員都是人類,但很多人並不是僱員,可能

是學生,自由職業者,兒童等。因此 C#語言規定,基類的參照變數可以引用其衍生類對

象,但衍生類的參照變數不可以引用其基類對象。

1.8 類的成員類的成員類的成員類的成員

由於 C#程式中每個變數或函數都必須屬於一個類或結構,不能像 C或 C++那樣建立全域變

數,因此所有的變數或函數都是類或結構的成員。類的成員可以分為兩大類:類本身所宣告的

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 28: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

28

以及從基類中繼承來的。

1.8.1 類的成員類型類的成員類型類的成員類型類的成員類型

類的成員包括以下類型:

� 局部變數:在 for、switch等語句中和類方法中定義的變數,只在指定範圍內有效。

� 欄位:即類中的變數或常數,包括靜態欄位、實例欄位、常數和唯讀欄位。

� 方法成員:包括靜態方法和實例方法。

� 屬性:按屬性指定的 get方法和 set方法對欄位進行讀寫。屬性本質上是方法。

� 事件:代表事件本身,同時聯繫事件和事件處理函數。

� 索引子:允許像使用陣列那樣存取類中的資料成員。

� 運算子多載:採用多載運算子的方式定義類中特有的操作。

� 建構函數和解構函數。

包含有可執行程式碼的成員被認為是類中的函數成員,這些函數成員有方法、屬性、索引

子、運算子多載、建構函數和解構函數。

1.8.2 類成員類成員類成員類成員存取存取存取存取修飾符修飾符修飾符修飾符

存取修飾符用於指定類成員的可存取性,C#存取修飾符有 private、protected、public 和

internal 四種。private 宣告私有成員,私有資料成員只能被類內部的函數使用和修改,私有函

數成員只能被類內部的函數調用。衍生類雖然繼承了基類私有成員,但不能直接存取它們,只

能通過基類的公有成員存取。protected 宣告保護成員,保護資料成員只能被類內部和衍生類

的函數使用和修改,保護函數成員只能被類內部和衍生類的函數調用。public 宣告公有成員,

類的公用函數成員可以被類的外部程序所調用,類的公用資料成員可以被類的外部程序直接使

用。公有函數實際是一個類和外部通訊的介面,外部函數通過調用公有函數,按照預先設定好

的方法修改類的私有成員和保護成員。internal 宣告內部成員,內部成員只能在同一程序集中

的文件中才是可以存取的,一般是同一個應用(Application)或庫(Library)。

1.9 類的類的類的類的欄位欄位欄位欄位和屬性和屬性和屬性和屬性

類或結構中定義的變數和常數一般稱為「欄位」。屬性不是欄位,本質上是定義修改欄位

的方法,由於屬性和欄位的緊密關係,把它們放到一起敘述。

1.9.1 靜態靜態靜態靜態欄位欄位欄位欄位、、、、實例實例實例實例欄位欄位欄位欄位、、、、常數常數常數常數和和和和唯讀欄位唯讀欄位唯讀欄位唯讀欄位

用修飾符 static 宣告的欄位為靜態欄位。不管包含該靜態欄位的類生成多少個對象或根本

無對象,該欄位都只有一個實例,靜態欄位不能被撤銷。必須採用如下方式引用靜態欄位:類

名.靜態欄位名。如果類中定義的欄位不使用修飾符 static,該欄位為實例欄位,每產生該類的

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 29: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

29

一個對象,在對象內產生一個該欄位實例,產生它的對象被撤銷,該欄位對象也被撤銷,實例

欄位採用如下方式引用:實例名.實例欄位名。用 const 修飾符宣告的欄位為常數,常數只能

在宣告中初始化,以後不能再修改。用 readonly 修飾符宣告的欄位為唯讀欄位,唯讀欄位是

特殊的實例欄位,它只能在欄位宣告中或建構函數中重新指派值,在其它任何地方都不能改變

唯讀欄位的值。例子:

public class Test

{

public const int intMax = int.MaxValue;//常數,必須賦初值

public int x = 0;//實例欄位

public readonly int y = 0;//唯讀欄位

public static int cnt = 0;//靜態欄位

public Test(int x1, int y1)//建構函數

{

//intMax = 0;//錯誤,不能修改常數

x = x1;//在建構函數允許修改實例欄位

y = y1;//在建構函數允許修改唯讀欄位

cnt++;//每產生一個對象都調用建構函數,用此語句可以記錄對象的個數

}

public void Modify(int x1,int y1)

{

//intMax = 0;//錯誤,不能修改常數

x = x1;

cnt = y1;

//y = 10;//不允許修改唯讀欄位

}

}

class Class1

{

static void Main(string[] args)

{

Test T1 = new Test(100,200);

T1.x = 40;//引用實例欄位採用:實例名.實例欄位名

Test.cnt = 0;//引用靜態欄位採用:類名.靜態欄位名

int z = T1.y;//引用唯讀欄位

z = Test.intMax;//引用常數

}

}

Page 30: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

30

1.9.2 屬性屬性屬性屬性(Property)

C#語言支援組件編程,組件也是類,組件用屬性、方法、事件描述。屬性不是欄位,但必

然和類中的某個或某些欄位相聯繫,屬性定義了得到和修改相聯繫的欄位的方法。C#中的屬性

更充分地體現了對象的封裝性:不直接操作類的資料內容,而是通過存取器進行存取,借助於

get 和 set 方法對屬性的值進行讀寫。存取屬性值的語法形式和存取一個變數基本一樣,使存

取屬性就像存取變數一樣方便,符合習慣。

在類的基本概念一節中,定義一個描述個人情況的類 Person,其中欄位 name和 age是私

有欄位,記錄姓名和年齡,外部通過公有方法 SetName和 SetAge修改這兩個私有欄位。現在

用屬性來描述姓名和年齡。例子如下:

using System;

public class Person

{

private string P_name = "張三";//P_name是私有欄位

private int P_age = 12;//P_age是私有欄位

public void Display()//類的方法宣告,顯示姓名和年齡

{

Console.WriteLine("姓名:{0},年齡:{1}", P_name,P_age);

}

public string Name//定義屬性 Name

{

get

{ return P_name; }

set

{ P_name = value; }

}

public int Age//定義屬性 Age

{

get

{ return P_age; }

set

{ P_age = value; }

}

}

public class Test

{

public static void Main()

Administrator
鉛筆
Administrator
鉛筆
Page 31: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

31

{

Person OnePerson = new Person();

OnePerson.Name = "田七";//value="田七",通過 set方法修改變數 P_Name

string s = OnePerson.Name;//通過 get方法得到變數 P_Name值

OnePerson.Age = 20;//通過定義屬性,既保證了姓名和年齡按指定方法修改

int x = OnePerson.Age;//語法形式和修改、得到一個變數基本一致,符合習慣

OnePerson.Display();

}

}

在屬性的存取宣告中,只有 set 存取器表明屬性的值只能進行設置而不能讀出,只有 get

存取器表明屬性的值是唯讀的不能改寫,同時具有 set 存取器和 get 存取器表明屬性的值的讀

寫都是允許的。

雖然屬性和欄位的語法比較類似,但由於屬性本質上是方法,因此不能把屬性當做變數那

樣使用,也不能把屬性作為傳參照參數或輸出參數來進行傳遞。

1.10 類的方法類的方法類的方法類的方法

方法是類中用於執行計算或其它行為的成員。所有方法都必須定義在類或結構中。

1.10.1 方法的方法的方法的方法的宣告宣告宣告宣告

方法的宣告格式如下:

屬性 方法修飾符 返回型別 方法名 ( 形參列表 ) { 方法體 }

方法修飾符包括 new、public、protected、internal、private、static、virtual、sealed、override、

abstract 和 extern。這些修飾符有些已經介紹過,其它修飾符將逐一介紹。返回型別可以是任

何合法的 C#資料型別,也可以是 void,即無返回值。形參列表的格式為:(形參型別 形參 1, 形

參型別 形參 2, ...),可以有多個形參。不能使用 C語言的形參格式。

1.10.2 方法參數的種類方法參數的種類方法參數的種類方法參數的種類

C#語言的方法可以使用如下四種參數(請注意和參數型別的區別):

� 傳值參數,不含任何修飾符。

� 傳參照參數,以 ref修飾符宣告。

� 輸出參數,以 out修飾符宣告。

� 參量參數,以 params修飾符宣告。

1. 傳值參數

當用傳值參數向方法傳遞參數時,程序複製實參的值,並且將此副本傳遞給該方法,被調

用的方法不會修改實參的值,所以使用傳值參數時,可以保證實參的值是安全的。如果參數型

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 32: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

32

別是參照型別,例如是類的參照變數,則副本中儲存的也是對象的參照,所以副本和實參引用

同一個對象,通過這個副本,可以修改實參所引用的對象中的資料成員。

2. 傳參照參數

有時在方法中,需要修改或得到方法外部的變數值,C語言是向方法傳遞實參指標來達到

目的,而 C#語言是用傳參照參數。當用傳參照參數向方法傳遞實參時,程序將把實參的參照,

即實參在記憶體中的地址傳遞給方法,方法通過實參的參照(地址),修改或得到方法外部的變

數值。傳參照參數以 ref修飾符宣告。注意在使用前,實參變數必須被設置初始值。

3. 輸出參數

為了把方法的運算結果保存到外部變數,因此需要知道外部變數的參照(地址)。輸出參數

用於向方法傳遞外部變數參照(地址),所以輸出參數也是傳參照參數,與傳參照參數的差別在

於調用方法前無需對變數進行初始化。在方法返回後,傳遞的變數被認為經過了初始化。傳值

參數、傳參照參數和輸出參數的用法見下例:

using System;

class g{ public int a = 0; }//類定義

class Class1

{

public static void F1(ref char i)//傳參照參數

{ i = 'b';}

public static void F2(char i)//傳值參數,參數型別為實值型別

{ i = 'd';}

public static void F3(out char i)//輸出參數

{ i = 'e';}

public static void F4(string s)//傳值參數,參數型別為字串

{ s = "xyz";}

public static void F5(g gg)//傳值參數,參數型別為參照型別

{ gg.a = 20;}

public static void F6(ref string s)//傳參照參數,參數型別為字串

{ s = "xyz";}

static void Main(string[] args)

{

char a = 'c';

string s1 = "abc";

F2(a);//傳值參數,不能修改外部的 a

Console.WriteLine(a);//因 a未被修改,顯示 c

F1(ref a);//傳參照參數,函數修改外部的 a的值

Console.WriteLine(a);//a被修改為 b,顯示 b

char j;

F3(out j);//輸出參數,結果輸出到外部變數 j

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 33: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

33

Console.WriteLine(j);//顯示 e

F4(s1);//傳值參數,參數型別是字串,s1為字串參照變數

Console.WriteLine(s1);//顯示:abc,字串 s1不被修改

g g1 = new g();

F5(g1);//傳值參數,但實參是一個類參照型別變數

Console.WriteLine(g1.a.ToString());//顯示:20,修改對象資料

F6(ref s1);//傳參照參數,參數型別是字串,s1為字串參照變數

Console.WriteLine(s1);//顯示:xyz,字串 s1被修改

}

}

4. 參量參數

參量參數使用 params修飾符,如果形參列中包含了參量參數,那麼它必須是參數表中最

後一個參數,參量參數只允許是一維陣列。比如 string[]和 string[][]型別都可以作為參量型參

數。最後,參量型參數不能再有 ref和 out修飾符。見下例:

using System;

class Class1

{

static void F(params int[] args)//參量參數,有 params修飾符

{

Console.Write("Array contains {0} elements:", args.Length);

foreach (int i in args)

Console.Write(" {0}", i);

Console.WriteLine();

}

static void Main(string[] args)

{

int[] a = {1, 2, 3};

F(a);//實參為陣列類參照變數 a

F(10, 20, 30, 40);//等價於 F(new int[] {60, 70, 80, 90});

F(new int[] {60, 70, 80, 90});//實參為陣列類參照

F();//等價於 F(new int[] {});

F(new int[] {});//實參為陣列類參照,陣列無元素

}

}

程序輸出

Array contains 3 elements: 1 2 3

Array contains 4 elements: 10 20 30 40

Array contains 4 elements: 60 70 80 90

Administrator
鉛筆
Administrator
鉛筆
Page 34: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

34

Array contains 0 elements:

Array contains 0 elements:

方法的參數為陣列時也可以不使用 params,此種方法可以使用一維或多維陣列,見下例:

using System;

class Class1

{

static void F(int[,] args)//傳值參數,參數型別為陣列類參照變數,無 params修飾

{

Console.Write("Array contains {0} elements:", args.Length);

foreach (int i in args)

Console.Write(" {0}", i);

Console.WriteLine();

}

static void Main(string[] args)

{

int[,] a = {{1, 2, 3}, {4, 5, 6}};

F(a);//實參為陣列類參照變數 a

//F(10, 20, 30, 40);//此格式不能使用

F(new int[,] {{60, 70},{80, 90}});//實參為陣列類參照

//F();//此格式不能使用

//F(new int[,] {});//此格式不能使用

}

}

程序輸出

Array contains 3 elements: 1 2 3 4 5 6

Array contains 4 elements: 60 70 80 90

1.10.3 靜態方法和實例方法靜態方法和實例方法靜態方法和實例方法靜態方法和實例方法

用修飾符 static 宣告的方法為靜態方法,不用修飾符 static 宣告的方法為實例方法。不管

類有否產生對象,類的靜態方法都可以被使用,使用格式為:類名.靜態方法名。靜態方法只

能使用該靜態方法所在類的靜態資料成員和靜態方法。這是因為使用靜態方法時,該靜態方法

所在類可能還沒有對象,即使有對象,由於用類名.靜態方法名方式調用靜態方法,靜態方法

沒有 this 指標來存放對象的地址,無法判定應存取哪個對象的資料成員。在類產生對象後,

實例方法才能被使用,使用格式為:對象名.實例方法名。實例方法可以使用該方法所在類的

所有靜態成員和實例成員。例子如下:

using System;

public class UseMethod

Administrator
鉛筆
Administrator
鉛筆
Page 35: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

35

{

private static int x = 0;//靜態欄位

private int y = 1;//實例欄位

public static void StaticMethod()//靜態方法

{

x = 10;//正確,靜態方法存取靜態資料成員

//y = 20;//錯誤,靜態方法不能存取實例資料成員

}

public void NoStaticMethod()//實例方法

{

x = 10;//正確,實例方法存取靜態資料成員

y = 20;//正確,實例方法存取實例資料成員

}

}

public class Class1

{

public static void Main()

{

UseMethod m = new UseMethod();

UseMethod.StaticMethod();//使用靜態方法格式為:類名.靜態方法名

m.NoStaticMethod();//使用實例方法格式為:對象名.實例方法名

}

}

1.10.4 方法的方法的方法的方法的多載多載多載多載

在 C#語言中,如果在同一個類中定義的函數名相同,而參數型別或參數個數不同,認為

是不相同的函數,僅返回值不同,不能看作不同函數,這叫做函數的多載。前面 Person 類中

定義了多個建構函數就是多載的例子。在 C 語言中,若計算一個資料的絕對值,則需要對不

同資料型別求絕對值方法使用不同的方法名,如 abc()求整數絕對值,labs()求長整數絕對值,

fabs()求浮點數絕對值。而在 C#語言中,可以使用函數多載特性,對這三個函數定義同樣的函

數名,但使用不同的參數型別。下面是實作方式:

using System;

public class UseAbs

{

public int abs(int x)//整數求絕對值

{ return(x<0 ? –x : x); }

public long abs(long x)//長整數求絕對值

Administrator
鉛筆
Administrator
鉛筆
Page 36: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

36

{ return(x<0 ? –x : x); }

public double abs(double x)//浮點數求絕對值

{ return(x<0 ? –x : x); }

}

class Class1

{

static void Main(string[] args)

{

UseAbs m=new UseAbs();

int x = –10;

long y = –123;

double z = –23.98d;

x = m.abs(x);

y = m.abs(y);

z = m.abs(z);

Console.WriteLine("x={0}, y={1}, z={2}", x, y, z);

}

}

類的對象調用這些同名方法,在編譯時,根據調用方法的實參型別決定調用那個同名方

法,計算不同型別資料的絕對值。這給編程提供了極大方便。

1.10.5 運算子運算子運算子運算子多載多載多載多載

運算子多載是 C#語言中的已有運算子賦予新的功能,但與該運算子的本來含義不衝突,

使用時只需根據運算子出現的位置來判別其具體執行哪一種運算。運算子多載,實際是定義了

一個運算子函數,運算子函數宣告的格式如下:

static public 函數返回型別 operator 重新定義的運算子(形參列表)

C#語言中有一些運算子是可以多載的,例如:+ – ! ~ ++ -- true false * / % & | ^ << >> == != >

< >= <=等等。但也有一些運算子是不允許進行多載的,例如:=、&&、||、?: 、new、typeof、

sizeof、is等。下面的例子,定義一個複數類,並且希望複數的加減乘除用符號+、–、*、/來表

示。

using System;

class Complex//複數類定義

{

private double Real;//複數實部

private double Imag;//複數虛部

public Complex(double x,double y)//建構函數

{

Administrator
鉛筆
Administrator
鉛筆
Page 37: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

37

Real = x;

Imag = y;

}

static public Complex operator – (Complex a)//多載一元運算子負號,注意 1個參數

{ return (new Complex(–a.Real, –a.Imag)); }

static public Complex operator +(Complex a, Complex b)//多載二元運算子加號

{ return (new Complex(a.Real+b.Real, a.Imag+b.Imag));}

public void Display()

{ Console.WriteLine("{0}+({1})j", Real,Imag); }

}

class Class1

{

static void Main(string[] args)

{

Complex x = new Complex(1.0, 2.0);

Complex y = new Complex(3.0, 4.0);

Complex z = new Complex(5.0, 7.0);

x.Display();//顯示:1+(2)j

y.Display();//顯示:3+(4)j

z.Display();//顯示:5+(7)j

z = –x;//等價於 z = opeator–(x)

z.Display();//顯示:–1+(–2)j

z = x+y;//即 z=opeator+(x,y)

z.Display();//顯示:4+(6)j

}

}

1.10.6 this關鍵關鍵關鍵關鍵字字字字

每個類都可以有多個對象,例如定義 Person 類的兩個對象:

Person P1 = new Person("李四",30);

Person P2 = new Person("張三",40);

因此 P1.Display()應顯示李四訊息,P2.Display()應顯示張三訊息,但無論產生多少個對象,只有

一個方法 Display(),該方法是如何知道顯示那個對象的訊息的呢?C#語言用參照變數 this 記錄

調用方法 Display()的對象,當某個對象調用方法 Display()時,this 便引用該對象(記錄該對象的

地址)。因此,不同的對象調用同一方法時,方法便根據 this 所引用的不同對象來確定應該引

用哪一個對象的資料成員。this 是類中隱含的參照變數,它是被自動被指派值的,可以使用但

Page 38: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

38

不能被修改。例如:P1.Display(),this 引用對象 P1,顯示李四訊息。P2.Display(),this 引用對

象 P2,顯示張三訊息。

1.10.7 靜態建構函數靜態建構函數靜態建構函數靜態建構函數

靜態建構函數用以初始化一些靜態欄位或唯讀欄位。如果有必要,可以為類別宣告靜態建

構函數。靜態建構函數的條件是:一個類別只能有一個、不可以有參數、不能存取實例成員─

包括 this,也不可加上 public和 private修飾符。靜態建構函數的執行時機在任何靜態成員被存

取或任何類實例生成之前,你可以讓形式完全相同的非靜態建構函數與之並存。例如:

class SomeClass

{

public static int x;

static SomeClass() //靜態建構函數

{

x = 1;

Console.WriteLine("SomeClass初始化");

}

public SomeClass()

{ Console.WriteLine("非靜態建構函數"); }

public static void Foo()

{ Console.WriteLine("Foo"); }

}

class Test

{

static void Main(string[] args)

{

//這三行都會啟動靜態建構函數

SomeClass sc = new SomeClass();

SomeClass.Foo();

Console.WriteLine(SomeClass.x);

}

}

1.11 類的類的類的類的多形多形多形多形性性性性

在物件導向的系統中,多形性是一個非常重要的概念。C#支援兩種類型的多形性,第一種

是編譯時的多形性,一個類的對象調用若干同名方法,系統在編譯時,根據調用方法的實參型

別及實參的個數決定調用那個同名方法,實現何種操作。編譯時的多形性是通過方法多載來實

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 39: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

39

現的。C#語言的方法多載以及運算子多載和 C++語言的基本一致。

第二種是執行時的多形性,是在系統執行時,不同對象調用一個名字相同,參數的型別及

個數完全一樣的方法,會完成不同的操作。C#執行時的多形性通過虛方法實現。在類的方法宣

告前加上了 virtual修飾符,被稱之為虛方法,反之為非虛方法。C#語言的虛方法和 C++語言的

基本一致。下面的例子說明了虛方法與非虛方法的區別:

using System;

class A

{

public void F()//非虛方法

{ Console.Write(" A.F"); }

public virtual void G()//虛方法

{ Console.Write(" A.G"); }

}

class B: A//A類為 B類的基類

{

new public void F()//覆蓋基類的同名非虛方法 F(),注意使用 new

{ Console.Write(" B.F"); }

public override void G()//覆蓋基類的同名虛方法 G(),注意使用 override

{ Console.Write(" B.G"); }

}

class Test

{

static void F2(A aA)//注意,參數為 A類參照變數

{ aA.G();}

static void Main()

{

B b = new B();

A a1 = new A();

A a2 = b;//允許基類參照變數引用衍生類對象,a2引用衍生類 B對象 b

a1.F();//調用基類 A的非虛方法 F(),顯示 A.F

a2.F();//F()為非虛方法,調用基類 A的 F(),顯示 A.F

b.F();//F()為非虛方法,調用衍生類 B的 F(),顯示 B.F

a1.G();//G()為虛方法,因 a1引用基類 A對象,調用基類 A的 G(),顯示 A.G

a2.G();/*G()為虛方法,因 a2引用衍生類 B對象,調用衍生類 B的 G(),顯示 B.G */

F2(b);//實參為衍生類 B對象,由於 A aA=b,調用衍生類 B的函數 G(),顯示 B.G

F2(a1);//實參為基類 A對象,調用 A類的函數 G(),顯示 A.G

}

}

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 40: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

40

那麼輸出應該是:

A.F A.F B.F A.G B.G B.G A.G

注意例子中,不同對象調用同名非虛方法 F()和同名虛方法 G()的區別。a2 雖然是基類參照變

數,但它引用衍生類對象 b。由於 G()是虛方法,因此 a2.G()調用衍生類 B的 G(),顯示 G.F。但

由於 F()是非虛方法,a2.F()仍然調用基類 A的 F(),顯示 A.F。或者說,如果將基類參照變數引

用不同對象,或者是基類對象,或者是衍生類對象,用這個基類參照變數分別調用同名虛方法,

根據對象不同,會完成不同的操作。而非虛方法則不具備此功能。

方法 F2(A aA)中,參數是 A類型別,F2(b)中形參和實參的關係是:A aA=b,即基類參照變

數 aA引用衍生類對象 b,aA.G()調用衍生類 B的函數 G(),顯示 B.G。同理,F2(a1)實參為基類 A

對象,調用 A類的函數 G(),顯示 A.G。

在類的基本概念一節中,定義一個描述個人情況的類 Person,其中公有方法 Display()用來

顯示個人訊息。在衍生僱員類 Employee 中,覆蓋了基類的公有方法 Display(),以顯示僱員新

增加的訊息。我們希望隱藏這些細節,希望無論基類還是衍生類,都調用同一個顯示方法,根

據對象不同,自動顯示不同的訊息。可以用虛方法來實現,這是一個典型的多形性例子。例子

using System;

public class Person

{

private String name = "張三";//類的資料成員宣告

private int age = 12;

protected virtual void Display()//類的虛方法

{ Console.WriteLine("姓名:{0},年齡:{1}",name,age); }

public Person(string Name, int Age)//建構函數,函數名和類同名,無返回值

{

name = Name;

age = Age;

}

static public void DisplayData(Person aPerson)//靜態方法

{ aPerson.Display(); }//不是靜態方法調用實例方法,如寫為 Display()錯誤

}

public class Employee:Person//Person類是基類

{

private string department;

private decimal salary;

public Employee(string Name, int Age,string D, decimal S) : base(Name, Age)

{

department = D;

salary = S;

}

Page 41: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

41

protected override void Display()//多載虛方法,注意用 override

{

base.Display();//存取基類同名方法

Console.WriteLine("部門:{0} 工資:{1} ", department,salary);

}

}

class Class1

{

static void Main(string[] args)

{

Person OnePerson = new Person("李四",30);

Person.DisplayData(OnePerson);//顯示基類資料

Employee OneEmployee = new Employee("王五",40,"財務部",2000);

Person.DisplayData(OneEmployee); //顯示衍生類資料

}

}

執行後,顯示的效果是: 姓名:李四,年齡:30 姓名:王五,年齡:40 部門:財務部 工資:2000

1.12 抽像類和抽像方法抽像類和抽像方法抽像類和抽像方法抽像類和抽像方法

抽像類表示一種抽像的概念,只是希望以它為基類的衍生類有共同的函數成員和資料成

員。抽像類使用 abstract修飾符,對抽像類的使用有以下幾點規定:

� 抽像類只能作為其它類的基類,它不能直接被實例化。

� 抽像類允許包含抽像成員,雖然這不是必須的。抽像成員用 abstract修飾符修飾。

� 抽像類不能同時又是密封的。

� 抽像類的基類也可以是抽像類。如果一個非抽像類的基類是抽像類,則該類必須通過覆蓋

來實現所有繼承而來的抽像方法,包括其抽像基類中的抽像方法,如果該抽像基類從其它

抽像類衍生,還應包括其它抽像類中的所有抽像方法。

請看下面的例子:

abstract class Figure//抽像類定義

{

protected double x = 0, y = 0;

public Figure(double a, double b)

{

x = a;

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 42: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

42

y = b;

}

public abstract void Area();//抽像方法,無實作程式碼

}

class Square : Figure///類 Square定義

{

public Square(double a, double b) : base(a, b)

{ }

public override void Area()//不能使用 new,必須用 override

{ Console.WriteLine("矩形面積是:{0}", x*y);}

}

class Circle:Figure///類 Square定義

{

public Circle(double a):base(a,a)

{}

public override void Area()

{ Console.WriteLine("圓面積是:{0}", 3.14*x*y); }

}

class Class1

{

static void Main(string[] args)

{

Square s = new Square(20, 30);

Circle c = new Circle(10);

s.Area();

c.Area();

}

}

程序輸出結果為:

矩形面積是:600

圓面積是:314

抽像類 Figure 提供了一個抽像方法 Area(),並沒有實現它,類 Square 和 Circle 從抽像類

Figure中繼承方法 Area(),分別具體實現計算矩形和圓的面積。

在類的基本概念一節中,定義一個描述個人情況的類 Person,它只是描述了一個人最一般

的屬性和行為,因此不希望生成它的對象,可以定義它為抽像類。

注意:C++程式設計師在這裡最容易犯錯誤。C++中沒有對抽像類進行直接宣告的方法,而

認為只要在類中定義了純虛函數,這個類就是一個抽像類。純虛函數的概念比較晦澀,直觀上

不容易為人們接受和掌握,因此 C#拋棄了這一概念。

Page 43: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

43

1.13 密封類和密封方法密封類和密封方法密封類和密封方法密封類和密封方法

有時候,我們並不希望自己編寫的類被繼承。或者有的類已經沒有再被繼承的必要。C#

提出了一個密封類(sealed class)的概念,幫助開發人員來解決這一問題。

密封類在宣告中使用 sealed修飾符,這樣就可以防止該類被其它類繼承。如果試圖將一個

密封類作為其它類的基類,C#編譯器將提示出錯。理所當然,密封類不能同時又是抽像類,因

為抽像總是希望被繼承的。

C#還提出了密封方法(sealed method)的概念。方法使用 sealed修飾符,稱該方法是一個密

封方法。在衍生類中,不能覆蓋基類中的密封方法。

1.14 介面介面介面介面

與類一樣,在介面中可以定義一個和多個方法、屬性、索引子和事件。但與類不同的是,

介面中僅僅是它們的宣告,並不提供實作。因此介面是函數成員宣告的集合。如果類或結構從

一個介面衍生,則這個類或結構負責實作該介面中所宣告的所有成員。一個介面可以從多個介

面繼承,而一個類或結構可以實作多個介面。由於 C#語言不支援多重繼承,因此,如果某個

類需要繼承多個類的行為時,只能使用多個介面加以描述。

1.14.1 介面宣告介面宣告介面宣告介面宣告

介面宣告是一種型別宣告,它定義了一種新的介面型別。介面宣告格式如下:

屬性介面修飾符 interface 介面名:基介面 { 介面體 }

其中,關鍵字 interface、介面名和介面體時必須的,其它項是可選的。介面修飾符可以是 new、

public、protected、internal和 private。例子:

public interface IExample

{

//所有介面成員都不能包括實作

string this[int index] { get; set; }//索引子宣告

event EventHandler E;//事件宣告

void F(int value);//方法宣告

string P { get; set;}//屬性宣告

}

宣告介面時,需注意以下內容:

� 介面成員只能是方法、屬性、索引子和事件,不能是常數、欄位、運算子、建構函數或解

構函數,不能包含任何靜態成員。

� 介面成員宣告不能包含任何修飾符,介面成員預設的存取方式是 public。

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 44: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

44

1.14.2 介面介面介面介面的繼承的繼承的繼承的繼承

類似於類的繼承性,介面也有繼承性。衍生介面繼承了基介面中的函數成員說明。介面允

許多重繼承,一個衍生介面可以沒有基介面,也可以有多個基介面。在介面宣告的冒號後列出

被繼承的介面名字,多個介面名之間用分號分割。例子如下:

using System;

interface IControl

{ void Paint(); }

interface ITextBox : IControl//繼承了介面 Icontrol的方法 Paint()

{ void SetText(string text); }

interface IListBox : IControl//繼承了介面 Icontrol的方法 Paint()

{ void SetItems(string[] items); }

interface IComboBox : ITextBox, IListBox

{ /* 可以宣告新方法 */ }

上面的例子中,介面 ITextBox和 IListBox都從介面 IControl中繼承,也就繼承了介面 IControl

的 Paint 方法。介面 IComboBox 從介面 ITextBox 和 IListBox 中繼承,因此它應該繼承了介面

ITextBox的 SetText方法和 IListBox的 SetItems方法,還有 IControl的 Paint方法。

1.14.3 類對類對類對類對介面介面介面介面的實的實的實的實作作作作

前面已經說過,介面定義不包括函數成員的實作部分。繼承該介面的類或結構應實作這些

函數成員。這裡主要講述通過類來實作介面。類實作介面的本質是,用介面規定類應實作那些

函數成員。用類來實作介面時,介面的名稱必須包含在類宣告中的基類列表中。

在類的基本概念一節中,定義一個描述個人情況的類 Person,從類 Person 可以衍生出其

它類,例如:工人類、公務員類、醫生類等。這些類有一些共有的方法和屬性,例如工資屬性。

一般希望所有衍生類存取工資屬性時用同樣變數名。該屬性定義在類 Person 中不合適,因為

有些人無工資,如小孩。如定義一個類作為基類,包含工資屬性,但 C#不支援多重繼承。可

行的辦法是使用介面,在介面中宣告工資屬性。工人類、公務員類、醫生類等都必須實作該介

面,也就保證了它們存取工資屬性時用同樣變數名。例子如下:

using System;

public interface I_Salary//介面

{

decimal Salary//屬性宣告

{ get; set; }

}

public class Person

{…//見 1.9.2屬性節 Person類定義,這裡不重複了。

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 45: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

45

}

public class Employee:Person,I_Salary//Person類是基類,I_Salary是介面

{ //不同程式設計師完成工人類、醫生類等,定義工資變數名稱可能不同

private decimal salary;

public new void Display()

{

base.Display();

Console.WriteLine("工資:{0} ", salary);

}

//工人類、醫生類等都要實現屬性 Salary,保證使用的工資屬性同名

public decimal Salary

{

get { return salary; }

set { salary = value; }

}

}

public class Test

{

public static void Main()

{

Employee S = new Employee();

S.Name = "田七";//修改屬性 Name

S.Age = 20;//修改屬性 Age

S.Salary = 2000;//修改屬性 Salary

S.Display();

}

}

如果類實現了某個介面,類也隱式繼承了該介面的所有基介面,不管這些基介面有沒有在

類宣告的基類表中列出。因此,如果類從一個介面衍生,則這個類負責實現該介面及該介面的

所有基介面中所宣告的所有成員。

1.15 委派委派委派委派

在這裡要介紹的是 C#的一個參照型別─委派(delegate),也翻譯為代表。它實際上相當於

C語言的函數指標。與指標不同的是 C#中的委派是型別安全的。委派類宣告格式如下:

屬性集 修飾符 delegate 函數返回型別 定義的委派標識符(函數形參列表);

修飾符包括 new、public、protected、internal和 private。例如我們可以宣告一個返回型別為 int,

無參數的函數的委派MyDelegate:

Administrator
鉛筆
Page 46: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

46

public delegate int MyDelegate();//只能代表返回型別為 int,無參數的函數

宣告了委派類 MyDelegate,可以產生委派類 MyDelegate的對象,用這個對象去代表一個靜態

方法或非靜態的方法,所代表的方法必須為 int型別,無參數。看下面的例子:

using System;

delegate int MyDelegate();//宣告一個委派,注意宣告的位置

public class MyClass

{

public int InstanceMethod()//非靜態的方法,注意方法為 int型別,無參數

{

Console.WriteLine("調用了非靜態的方法。");

return 0;

}

static public int StaticMethod()//靜態方法,注意方法為 int型別,無參數

{

Console.WriteLine("調用了靜態的方法。");

return 0;

}

}

public class Test

{

static public void Main ()

{

MyClass p = new MyClass();

/* 用 new建立委派類 MyDelegate對象,d中儲存非靜態的方法 InstanceMethod的地址 */

MyDelegate d = new MyDelegate(p.InstanceMethod);//參數是被委派的方法

d();//調用非靜態方法

/* 用 new建立委派類 MyDelegate對象,d中儲存靜態的方法 StaticMethod的地址

*/

d = new MyDelegate(MyClass.StaticMethod);//參數是被委派的方法

d();//調用靜態方法

}

}

程序的輸出結果是: 調用了非靜態的方法。 調用了靜態的方法。

Page 47: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

47

1.15.1 複合複合複合複合委派委派委派委派(multicast delegate)

委派類的基類是MulticastDelegate,其建構函數必須有一個委派參數。一個複合委派可以

代表多個委派,如下例:

using System;

public delegate void GreetingDelegate(string name); //定義一種委派型別

public class MulticastDelegateApp

{

public static void Main()

{

/* 下行會編譯錯誤,委派的建構方法須有參數 */

//GreetingDelegate delegate1 = new GreetingDelegate();

GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);

delegate1 = EnglishGreeting; //此行與上一行等價

delegate1 += ChineseGreeting; //將委派加入複合委派

delegate1("Peng哥"); //調用委派

}

private static void EnglishGreeting(string name)

{

Console.WriteLine("Good morning, {0}!", name);

}

private static void ChineseGreeting(string name)

{

Console.WriteLine ("早安, {0}!", name);

}

}

當調用複合委派時,此委派所代表的所有委派全被調用。撤銷複合委派中的某個委派可以

用-=運算。

1.16 事件事件事件事件

事件是 C#語言內置的語法,可以定義和處理事件,為使用組件編程提供了良好的基礎。

1.16.1 事件驅動事件驅動事件驅動事件驅動

Windows 操作系統把用戶的動作都看作消息,C#中稱作事件,例如用鼠標左鍵單擊按鈕,

發出鼠標單擊按鈕事件。Windows 操作系統負責統一管理所有的事件,把事件發送到各個執

Administrator
鉛筆
Administrator
鉛筆
Page 48: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

48

行程序。各個程序用事件處理函數響應事件,這種方法也叫事件驅動。

C#語言使用組件編製Windows 應用程式。組件本質上是類。在組件類中,預先定義了該

組件能夠響應的事件,以及對應的事件函數,該事件發生,將自動調用自己的事件函數。例如,

按鈕類中定義了單擊事件 Click 和單擊事件函數。一個組件中定義了多個事件,應用程序中不

必也沒必要響應所有的事件,而只需響應其中很少事件,程式設計師撰寫相應的事件處理函

數,用來完成需要響應的事件所應完成的功能。現在的問題是,第一,如何把程式設計師撰寫

的事件處理函數和組件類中預先定義的事件函數聯繫起來。第二,如何使不需響應的事件無動

作。這是本節要節的解決問題。

1.16.2 事件的事件的事件的事件的宣告宣告宣告宣告

在 C#中是利用複合委派(或稱委派鏈)並搭配 event修飾符來完成事件處理。複合委派模型

是屬於發佈者/訂閱者模式,也就是某個類會宣告它會發佈的事件,任何其他類都可以訂閱這

些事件。事件在 C#中是委派類參照變數,有 event修飾符。例如按鈕類的單擊事件,按鈕是發

佈者,宣告代表單擊事件的複合委派成員。實作按鈕事件處理函數的類為訂閱者,訂閱者將處

理函數註冊到發佈者的委派中,即完成訂閱。發佈者發佈事件,即調用委派所代表的方法。表

示事件的委派型別,必須符合下列兩點要求:

1. 此委派型別必須有兩個參數,分別代表兩個對象:喚起事件的發佈者(publisher)和事件資訊。

2. 其中第二個參數一定要衍生自.NET Framework的 EventArgs類。

下面的例子定義了一個發佈者:Button 組件;這個例子不完整,只是說明問題。實際在

C#語言類庫中已預先定義了 Button組件,這裡的程式碼只是想說明 Button組件中是如何定義

事件的。例子如下:

public delegate void EventHandler(object sender, EventArgs e);//宣告委派型別

//EventHandler可以代表沒有返回值,參數為(object sender, EventArgs e)的函數

public class Button : Control//定義一個按鈕類 Button組件

{…//按鈕類 Button其它成員定義

public event EventHandler Click;//宣告一個事件 Click,是委派類參照變數

protected void OnClick(EventArgs e)//當單擊事件發生,觸發 OnClick方法

{

if(Click != null) //如果有訂閱者,Click已代表了事件處理函數

Click(this, e); //執行這個函數

}

public void Reset() //撤銷所有訂閱

{ Click = null; }

}

在這個例子中,按鈕單擊事件發生,應有程式碼保證(未列出)自動觸發 OnClick方法。Click

是類 Button的一個事件,同時也是委派類 EventHandler的參照變數,若 Click已代表了一些事

件處理函數,這些函數為 Click事件應完成的功能,Click事件發生時,執行事件處理函數。

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 49: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

49

1.16.3 事件的預訂和撤消事件的預訂和撤消事件的預訂和撤消事件的預訂和撤消

在隨後的例子中,我們宣告了一個使用 Button 類的登錄對話框類,對話框類含有兩個按

鈕:OK和 Cancel按鈕。對話框是按鈕事件的訂閱者,程式碼如下:

public class LoginDialog : Form//登錄對話框類宣告

{

Button OkButton;

Button CancelButton;

public LoginDialog()//建構函數

{

OkButton = new Button();//建立按鈕對象 OkButton

//Click代表 OkButtonClick方法,注意+=的使用

OkButton.Click += new EventHandler(OkButtonClick); //訂閱按鈕事件

CancelButton = new Button();//建立按鈕對象 OkButton

CancelButton.Click += new EventHandler(CancelButtonClick); //訂閱按鈕事件

}

void OkButtonClick(object sender, EventArgs e)

{…/* 處理 OkButton.Click事件的方法 */ }

void CancelButtonClick(object sender, EventArgs e)

{…/* 處理 CancelButton.Click事件的方法 */ }

}

在例子中建立了 Button類的兩個實例,單擊按鈕事件 Click通過如下語句和事件處理方法

聯繫在一起: OkButton.Click+=new EventHandler(OkButtonClick),該語句的意義是使

OkButton.Click 代表事件處理方法 OkButtonClick,這樣只要 Click 事件被觸發,事件處理方法

OkButtonClick 就會被自動調用。撤消事件和事件處理方法 OkButtonClick 的聯繫採用如下語句

實現:OkButton.Click –= new EventHandler(OkButtonClick),這時,OkButton.Click就不再代表事

件處理方法,Click 事件被觸發,方法 OkButtonClick 就不會被調用了。務必理解這兩條語句的

用法。使用 Visual Studio.Net集成環境可以自動建立這種聯繫,在自動生成的程式碼中包括這

兩條語句。

1.17 索引子索引子索引子索引子

在 C#語言中,陣列也是類,比如我們宣告一個整數陣列:int[] arr = new int[5],實際上生

成了一個陣列類對象,arr是這個對象的參照(地址),存取這個陣列元素的方法是:arr[下標],

在陣列類中,使用索引存取元素是如何實現的呢?是否可以定義自己的類,用索引存取類中的

資料成員?索引子(indexer)為我們提供了通過索引方式方便地存取類的資料成員的方法。

Administrator
鉛筆
Administrator
鉛筆
Page 50: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

50

首先看下面的例子,用於列印出小組人員的名單:

using System

class Team

{

string[] s_name = new string[2];//定義字串陣列,記錄小組人員姓名

public string this[int nIndex]//索引子宣告,this為類 Team類的對象

{

get//用對象名[索引]得到記錄小組人員姓名時,調用 get函數

{ return s_name[nIndex]; }

set//用對象名[索引]修改記錄小組人員姓名時,調用 set函數

{ s_name[nIndex] = value; }//value為被修改值

}

}

class Test

{

public static void Main()

{

Team t1 = new Team();

t1[0] = "張三";

t1[1] = "李斯";

Console.WriteLine("{0},{1}", t1[0], t1[1]);

}

}

顯示結果如下:張三,李斯

1.18 命名空間命名空間命名空間命名空間

一個應用程序可能包含許多不同的部分,除了自己編製的程序之外,還要使用作業系統或

開發環境提供的函數庫、類庫或組件庫,從軟件開發商處購買來的函數庫、類庫或組件庫,或

開發團隊中其它人編製的程序,等等。為了組織這些程式碼,使應用程序可以方便地使用這些

程式碼,C#語言提出了命名空間的概念。命名空間是函數、類或組件的容器,把它們按類別放

入不同的命名空間中,命名空間提供了一個邏輯上的層次結構體系,使應用程序能方便的找到

所需程式碼。這和 C語言中的 include語句的功能有些相似,但實作方法完全不同。

1.18.1 命名空間命名空間命名空間命名空間的的的的宣告宣告宣告宣告

用關鍵字 namespace宣告一個命名空間,命名空間的宣告可以是源文件 using語句後的第

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 51: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

51

一條語句,也可以是以成員的型式出現在其它命名空間的宣告之中,也就是說,在一個命名空

間內部還可以定義命名空間成員。全域命名空間應是源文件 using語句後的第一條語句。在同

一命名空間中,不允許出現同名命名空間成員或同名的類。在宣告時不允許使用任何存取修飾

符,命名空間隱式地使用 public修飾符。例子如下:

using System;

namespace N1//N1為全域命名空間的名稱,應是 using語句後的第一條語句

{

namespace N2//命名空間 N1的成員 N2

{

class A { void f1(){}; } //在 N2命名空間定義的類不應同名

class B { void f2(){}; }

}

}

也可以採用非嵌套的語法來實現以上命名空間:

namespace N1.N2//類 A、B在命名空間 N1.N2中

{

class A { void f1(){}; }

class B { void f2(){}; }

}

也可以採用如下格式:

namespace N1.N2//類 A在命名空間 N1.N2中

{

class A { void f1(){}; }

}

namespace N1.N2//類 B在命名空間 N1.N2中

{

class B { void f2(){}; }

}

1.18.2 命名空間命名空間命名空間命名空間使用使用使用使用

如在程式中,需引用其它命名空間的類或函數等,可以使用語句 using,例如需使用上節

定義的方法 f1()和 f2(),可以採用如下程式碼:

using N1.N2;

class WelcomeApp

{

public static void Main()

{

Administrator
鉛筆
Administrator
鉛筆
Page 52: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

52

A a=new A();

a.f1();

}

}

using N1.N2實際上是告訴應用程式到哪裡可以找到類 A。請讀者重新看一下 1.2.1節中的

例子。

1.19 非安全非安全非安全非安全程式碼程式碼程式碼程式碼

在 C和 C++的程式設計師看來,指標是最強有力的工具之一,同時又帶來許多問題。因為

指標指向的資料型別可能並不相同,比如你可以把 int型別的指標指向一個 float型別的變數,

而這時程序並不會出錯。如果你刪除了一個不應該被刪除的指標,比如 Windows 中指向主程

序的指標,程序就有可能崩潰。因此濫用指標給程序帶來不安全因素。正因為如此,在 C#語

言中取消了指標這個概念。雖然不使用指標可以完成絕大部分任務,但有時在程序中還不可避

免的使用指標,例如調用 Windows操作系統的 API函數,其參數可能是指標,所以在 C#中還

允許使用指標,但必須宣告這段程序是非安全(unsafe)的。可以指定一個方法是非安全的,例

如:unsafe void F1(int * p){…}。可以指定一條語句是非安全的,例如:unsafe int* p2=p1;還可

以指定一段程式碼是非安全的,例如:unsafe{ int* p2=p1; int* p3=p4;}。在編譯時要採用如下格

式:csc 要編譯的 C#源程序/unsafe。

習題習題習題習題

1. 從鍵盤輸入姓名,在顯示器中顯示對輸入姓名的問候。(提示:string 為字串型別,用語句

string s=Console.ReadLine()輸入姓名)

2. 建構函數和解構函數的主要作用是什麼?它們各有什麼特性?

3. 定義點(Point)類,資料成員為私有成員,增加有參數和無參數建構函數,在主函數中生成

點類對象,並用文字顯示點類對象的坐標。

4. 定義矩形類,資料成員為私有成員,增加有參數和無參數建構函數,在主函數中生成矩形

類對象,並用文字顯示矩形類對象的長、寬和矩形左上角的坐標。

5. 設計一個計數器類,統計鍵入回車(Return)的次數,資料成員為私有成員,在主程序中使用

此類統計鍵入回車的次數。

6. 說明實值型別和參照型別的區別,並和 C 語言相應型別比較。

7. 定義點結構,在主函數中生成點結構變數,從鍵盤輸入點的位置,並重新顯示坐標。

8. 定義整數一維陣列,從鍵盤輸入陣列元素數值後,用迴圈語句顯示所有元素的值。

9. 輸入字串,將字串第一個字母和每個空格後的字母變為大寫,其餘字母為小寫後輸出。

10. 輸入 5 個數,在每兩個數之間增加 3 個空格後輸出。

11. 編一個猜數程序,程序設定一個 1 位十進制數,允許用戶猜 3 次,錯了告訴比設定數大還

是小,用 switch 語句實現。

Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Administrator
鉛筆
Page 53: 第一章 C# 語言基礎 - Kun Shan Universityeportfolio.lib.ksu.edu.tw/user/T/H/4970E052-20110522235830.pdf · 第一章 C# 語言基礎 本章介紹C# 語言的基礎知識,希望具有C語言的讀者能夠基本掌握C#

53

12. C#語言 for 語句可以這樣使用:for(int i; i<10; i++){…},請問,i 的有效使用範圍。

13. 用字元*在顯示器上顯示一個矩形。

14. 輸入一個字串,用 foreach 語句計算輸入的字串長度,並顯示長度。

15. 輸入兩個數相加,並顯示和。用異常語句處理輸入錯誤。

16. 將 1.6.3 節中 try-catch-finally 語句例子改為 try-finally 和 try-catch 語句。

17. 定義點類,從點類衍生矩形類,資料成員為私有成員,增加有參數和無參數建構函數,在

主函數中產生矩形類對象,並用字串顯示矩形類對象的長、寬和矩形左上角的坐標。

18. 重做 12 題,將資料成員用屬性表示。

19. 定義一個類,將類外部的 char 陣列元素都變為大寫。主程序輸入一個字串,將其變為 char

陣列,變為大寫後輸出每一個 char 陣列元素。分別用類對象和靜態函數實現。

20. 定義分數類,實現用符號+,–,*,/完成分數的加減乘除。在主函數中輸入兩個數,完成

運算後輸出運算結果。

21. 建立一個 sroot()函數,返回其參數的二次根。多載它,讓它能夠分別返回整數、長整數和

雙精度參數的二次根。

22. 重新設計 complex 類,完成複數的+、–、*、/四則運算。

23. 定義點類,從點類衍生矩形類和圓類,主程序實現用同一個方法顯示矩形和圓的面積。

24. 重做 19 題,將點類定義為抽像類。

25. 重做 19 題,改為介面實作,即將點類改為介面。