目前分類:C# (53)

瀏覽方式: 標題列表 簡短摘要

C#是以.NET架構為基礎,由微軟開發的、一種高效能的物件導向程式語言,擁有C與C++的強大功能,且使用上更方便。

對於撰寫表單程式、用來控制windows內的許多內建功能也是很不錯的。

熟練後,可用於開發APP、演算法、人工智慧、電玩遊戲...等。

在google上搜尋:

"C# 下載" 或 "visiual studio下載"  

可進入微軟的官方網站,照著其步驟即可安裝。

 

 

以下是C#教學:

1. C# 基礎教學篇 (範例使用主控台應用程式)

C#主控台應用程式

C# 基本語法

C# 字串

C# if判斷式和邏輯運算子

C# 迴圈

C# 變數轉換

 

以下教學與範例,均使用表單應用程式

2. 表單應用程式

C# 表單應用程式

C# 表單

C# 多表單專案

 

3. 常用的控制項

C# button radiobutton checkbox NumericUpDown

C# label

C# LinkLabel

C# textbox

C# RichTextBox

C# 容器控制項

C# combobox

C# picturebox

C# messagebox

C# 日期與時間控制項

C# ProgressBar

C# Windows Media Player

C# 各控制項通用的語法、屬性、成員函式

 

4. 對話方塊(dialog)

對話方塊,是C#內建的控制項,裡頭包含著許多子控制項,讓程式使用者進行某些設定。一些微軟所開發出的軟體也會使用這些對話方塊。

註一(重要!):對話方塊也是控制項的一種,故需要在表單中建立才能使用。

註二:以下範例皆在Windows Form 應用程式中執行,且表單中已有一個TextBox控制項,名為tetxBox1,是用來顯示輸訊息的。表單中亦有一個Button控制項,名為button1,用來觸發事件。且,程式碼都寫在

public partial class Form1 : Form{} 的括號{} 之中,也就是說,格式是這樣的:

public partial class Form1 : Form

{

    範例程式碼

}

C# 字型對話方塊(FontDialog)

C# 顏色對話方塊(ColorDialog)

C# 檔案對話方塊(openfiledialog savefiledialog)

 

5. 事件(event)

C# 鍵盤滑鼠事件

參考資料 鍵盤按鍵名稱與按鍵編碼的對應表

 

6. 多元素容器

在此介紹的多元素容器有:陣列(Array)、清單(List)ArrayListSortedList以下是這四者的比較表:

 

陣列(Array)

清單(List)

ArrayList

SortedList

元素個數

不可變

可變

可變

可變

其元素的資料形態是否需要相同

需要相同

需要相同

不需要相同

不需要相同

序數

只能是整數

只能是整數

只能是整數

只能是整數

索引

同於序數

同於序數

同於序數

不同於序數,

可以是任何物件

教學連結如下:

C# Array

C# List

C# ArrayList

C# SortedList

 

7. 函式(function)

C# 建立函式

C# 函式參數傳遞

C# 多載

C# 子函式

C# delegate

C# 匿名函式

C# 遞迴函式

 

8. 類別(class)

C# 類別的宣告

C# 類別物件的宣告與使用

C# 類別的「成員」與「屬性」

C# 靜態成員與靜態成員函式

C# 類別物件的複製

C# 類別的繼承

 

9. 外部檔案處理(IO)

使用下列進行外部檔案處理,均需引用System.IO這個命名空間。即在程式碼開頭加入:

using System.IO;

這一行即可。

本章用詞:

徑物:代表一個路徑上的資料夾或檔案。

資料夾:和「目錄」是同一個意思。

C# 資料夾的處理

C# 路徑的處理

C# 檔案的處理

C# 檔案內容的讀寫(StreamReader、StreamWriter、FileStream)

 

10. 影像與繪圖

C# 影像(Image)

 

11. 常用內建物件

C# stopwatch計時器

C# 數學運算

C# tuple

 

 

 

按此前往程式語言教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(1) 人氣()

多元素結構物件,Tuple

Tuple擁有多個成員,其成員數可自訂。成員之資料型態可以自訂,亦可用類別物件來當作資料型態。常用於函式要回傳多個資料時,便將多個資料設成Tuple成員,然後回傳整個Tuple

以下情況,只適用於在Tuple之成員數目<=8之時。若大於8,此情況較為複雜,不在此細談。

(1) 建構:

Tuple<資料型態一, 資料型態二, 資料型態三…> Tuple名稱 = Tuple.Creat(資料一,資料二, 資料三…);

Tuple只有兩個成員,還可用以下方式建構:

Tuple<資料型態一, 資料型態二> Tuple名稱 = new Tuple<資料型態一, 資料型態二>(資料一,資料二);

(2) 常用成員:

Tuple名稱.Item1:即是該Tuple的資料一。

Tuple名稱.Item2:即是該Tuple的資料二。

Tuple名稱.Item3:即是該Tuple的資料三。

其他以此類推:Tuple名稱.ItemX:即是該Tuple的資料X

範例一:

Tuple<Point, Color> tp1 = new Tuple<Point, Color>(new Point(100,100), Color.Red);

Tuple<int, string> tp2 = new Tuple<int, string>(2, "nunu");

richTextBox1.Text += tp1.Item1 + "," + tp1.Item2 + "\r\n";

執行後,richTextBox1中顯示:

{X=100,Y=100},Color [Red]

範例二:

Tuple<int, string,int, bool, char> a = Tuple.Create(1, "3",1,true,'aaa');

richTextBox1.Text += a.Item5;

執行後,在richTextBox1中顯示:

aaa

 

 

上一篇:數學運算

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

數學運算:

Math.Abs(a):其中a可為浮點數或整數。該函式回傳a的絕對值。

Math.Max(a,b):其中ab可為浮點數或整數。該函式回傳ab兩者比較後的最大值。

Math.Min(a,b):其中ab可為浮點數或整數。該函式回傳ab兩者比較後的最小值。

Math.Round(a,b):其中a為浮點數、b為整數。該函式回傳a在小數點後第b位之四捨五入值。b可不寫,若不寫,則該函式將a四捨五入至整數後回傳。

Math.Ceiling(a):其中a為浮點數。該函式將a無條件進位至整數後回傳。

Math.Floor(a):其中a為浮點數。該函式將a之小數點部分無條件捨去後回傳。

Math.Pow(a,b):其中ab可為浮點數或整數。該函式回傳ab次方。

Math.Exp(a):其中a可為浮點數或整數。該函式回傳exp(2.718)a次方。

Math.Log(a,b):其中ab可為浮點數或整數。該函式回傳「以b為底數、以a為真數的log值」。

Math.Log(a):其中a可為浮點數或整數。該函式回傳「以exp(2.718)為底數、以a為真數的log值」。

Math.Cos(a):其中a可為浮點數或整數。該函式回傳cos(a)之值。其中a之單位為徑度。

Math.Sin(a):其中a可為浮點數或整數。該函式回傳sin(a)之值。其中a之單位為徑度。

Math.Tan(a):其中a可為浮點數或整數。該函式回傳tan(a)之值。其中a之單位為徑度。

 

 

亂數:

Random 隨機變數名稱 = new Random(Guid.NewGuid().GetHashCode());

隨機變數名稱.Next(N):其中N為整數。該函式回傳一個整數亂數x,且0 <= x < N

隨機變數名稱.Next(N1,N2):其中N1N2為整數。該函式回傳一個整數亂數x,且N1 <= x < N2

 

 

 

上一篇:stopwatch計時器

下一篇:tuple

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

用來計算程式執行時間的物件:Stopwatch物件

欲使用Stopwatch物件,需在程式碼開頭寫下:

using System.Diagnostics

(1) 宣告方式:

Stopwatch Stopwatch物件名稱 =  new Stopwatch();

(2) Stopwatch物件常用的成員:

Stopwatch物件名稱.IsRunning:一個bool。若Stopwatch物件正在計時則為true,反之則為false

Stopwatch物件名稱.Elapsed:一個timespan物件。表示該Stopwatch物件在計時開始到計時結束時,總共記錄的時間。該物件常用成員有:

Stopwatch物件名稱.Elapsed.Milliseconds:一個int。表示總共記錄的時間(以毫秒為單位)

Stopwatch物件名稱.Elapsed.Seconds:一個int。表示總共記錄的時間(以秒為單位)

(3) Stopwatch物件常用的成員函式:

Stopwatch物件.Reset():無回傳值。令該Stopwatch物件之計時器歸零。

Stopwatch物件.Start():無回傳值。令該Stopwatch物件開始計時。

Stopwatch物件.Stop():無回傳值。令該Stopwatch物件停止計時。

 

 

 

上一篇:影像(image)

下一篇:數學運算

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

()、影像

最常見的影像(image),就是「二進位影像」。凡是副檔名為bmp的影像檔,就是個二進位影像檔。二進位影像在C#中是個類別物件。

 

1.顏色物件:

(1) 建立一個顏色物件:

(1-1) Color 變數名稱 = Color.FromArgb(int R,int G,int B);

其中,RGB0~255的整數,表示該顏色的R值、G值、B值。A值預設為255

(1-2) Color 變數名稱 = Color.FromArgb(int A,int R,int G,int B);

其中,ARGB0~255的整數,表示該顏色的A值、R值、G值、B值。

(2) 顏色物件的成員:

顏色.A:該顏色的A(又稱alpha值,或「不透明度」),為0~255的整數。數字越高越不透明,越低越透明。

顏色.R:該顏色的R值,為0~255的整數。

顏色.G:該顏色的G值,為0~255的整數。

顏色.B:該顏色的B值,為0~255的整數。

2.位元圖片:

(1) 位元圖片物件的建構式:

(1-1) Bitmap 變數名稱=new Bitmap(int X,int Y);   

其中,XY都是正整數。表示建立一個空白的位元圖片(即其每一個像素的ARGB值都是0)。其寬度是X個像素,高度是Y個像素。例如:

Bitmap p1=new Bitmap(100,100);

(1-2) Bitmap 變數名稱=new Bitmap(string 路徑);

路徑中讀取位元圖片。

(1-3) Bitmap 變數名稱=new Bitmap(Image 影像);   

表示將該影像給存入此位元圖片。那麼,位元圖片的每一個像素的ARGB值、以及寬度和高度,都和該影像是一樣的。例如:

Image A=Image.FromFile("D:/User-Data/Desktop/f1.jpg");

Bitmap p1=new Bitmap(A);

(2) 位元圖片的寬與高:

位元圖片.Width為該圖片的寬,位元圖片.Height為該圖片的高。

(3) 取得位元圖片中,某一個像素點的顏色:

位元圖片.GetPixel(int X,int Y);

可以回傳一個顏色物件,該顏色是此位元圖片中,x座標為Xy座標為Y的像素之顏色。

註:位元圖片的像素座標,是從0開始數起。也就是說,一張寬100、高100的位元圖片,像素的XY座標都是從0~99

(4) 設定位元圖片中,某一個像素點的顏色:

位元圖片.SetPixel(int X, int Y, Color C);

在此位元圖片中,設定x座標為Xy座標為Y的像素其顏色為C

(5) 顯示圖片於picturebox上:

pictureBox1.Image = 位元圖片名稱;

範例如:

Bitmap B = new Bitmap(100, 100);

for (int i = 0; i < B.Width; i++)

{

for (int j = 0; j < B.Height; j++)

{ B.SetPixel(i, j, Color.FromArgb(i, j, 0)); }

}

pictureBox1.Image = B;

執行後顯示:

image

(6) 將此位元圖片存檔:

位元圖片.Save(檔案路徑, 檔案編碼格式);

其中,檔案路徑的資料形態是字串。檔案編碼格式則是個System.Drawing.Imaging.ImageFormat類別物件,這個物件可以決定圖檔要用哪種編碼格式來存檔。此物件常用的寫法如下:

System.Drawing.Imaging.ImageFormat.Bmp  //表示用Bmp檔的編碼方式存檔

System.Drawing.Imaging.ImageFormat.Jpeg  //表示用Jpeg檔的編碼方式存檔

System.Drawing.Imaging.ImageFormat.Gif  //表示用Gif檔的編碼方式存檔(Gif檔可顯示透明度、動態圖檔)

System.Drawing.Imaging.ImageFormat.Png  //表示用Png檔的編碼方式存檔(Png檔可顯示透明度)

System.Drawing.Imaging.ImageFormat.Icon  //表示將檔案存成一個windows Icon檔案,也就是桌面圖示的檔案

註一:若檔案編碼格式不寫,則預設Png檔的編碼方式存檔。

註二:檔案編碼格式乃是檔案的本質,不因檔案路徑中副檔名而改變。也就是說,若今有一個圖檔,其檔案編碼格式System.Drawing.Imaging.ImageFormat.Png,但檔案路徑"xxx.bmp ",則其仍然是個Png檔,只不過檔名是xxx.bmp。如此一來造成此檔案「名不符實」,會產生使用上的誤解,故要小心!

 

 

上一篇:檔案內容的讀寫(streamreader、streamwriter、files)

下一篇:stopwatch計時器

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

讀:電腦利用「指標」來從檔案讀取資料,指標的意義等同於「讀取位置」。比如,今有個文字檔案,內容是:abcde,一開始指標在檔案開頭的位置(a處,用數字0代表該指標所在位置),每讀取一個字元,指標就往後進一個字元(例如連續讀取了abc3個字元後,指標就在d處,用數字3代表該指標所在位置)。使用者可以利用程式碼來操控指標,以方便讀取自己所想要讀取的檔案內容。

寫:一個完整的「將字串寫入檔案」的過程,須依序包含四個步驟:建立串流物件à利用串流物件將字串寫入緩衝區(buffer)à將緩衝區的字串寫入檔案à關閉串流物件。串流物件有FileStream物件、StreamReader物件、StreamWriter物件。FileStream物件可用來讀和寫,StreamReader物件可用來讀取,StreamWriter物件可用來寫入。一一介紹如下。

(1) 將檔案資料看做位元組(byte)的形式,來讀寫它:

須利用到FileStream物件。FileStream物件的宣告方式:

FileStream 物件名稱 = new FileStream(String "路徑", FileMode FileMode物件 [ ,FileAccess FileAccess物件])

(1-1) FileStream物件常用的成員:

物件名稱.CanRead:一個bool。若為true表示該FileStream物件可對路徑上的檔案進行讀取,若為false則否。可否對檔案進行讀取,和該FileStream物件的FileMode物件之設定有關。

物件名稱.CanWrite:一個bool。若為true表示該FileStream物件可對路徑上的檔案進行寫入,若為false則否。可否對檔案進行寫入,和該FileStream物件的FileMode物件之設定有關。

物件名稱.Length:一個long(長整數)。代表路徑上檔案的byte數目。

物件名稱.Position:一個long(長整數)。代表該FileStream物件在路徑上檔案中,其指標的位置。

(1-2) FileStream物件常用的成員函式:

物件名稱.Seek(long N, SeekOrigin 參考點):回傳一個long。此函式可以將指標的位置設定為相對於參考點而言、往後進Nbyte的位置,並將設定完成後的位置回傳。參考點是一個SeekOrigin物件,SeekOrigin物件可用以下方法呼叫:

SeekOrigin.Begin:表示將參考點設在檔案的開頭。

SeekOrigin.Current:表示將參考點設在當前的指標位置。

SeekOrigin.End:表示將參考點設在檔案的末尾。

物件名稱.ReadByte():回傳一個int。此函式可以從當前的指標位置讀取一個byte,並將這個byte轉為整數、以int型態儲存而回傳。使用前提是該FileStream物件的FileAccess物件要允許讀取才行。而因英文、數字、標點符號均是一個byte,而中文卻是兩個byte,故此函式無法順利讀取中文。而讀取出來的int須轉化為字元才能顯現成文字,做法如:

cahr this_char = (char)物件名稱.ReadByte();

物件名稱.WriteByte(byte N):無回傳值。此函式可以從當前的指標位置,將一個byte型別的變數N(byte型別的變數,其允許值為0~255)轉化為字元,而直接寫入檔案。使用前提是該FileStream物件的FileAccess物件要允許寫入才行。

物件名稱.Close():無回傳值。此函式可以關閉該FileStream物件。FileStream物件使用完後建議關閉,以免占用系統資源。

(2) 將檔案資料看做文字(char(字元)string(字串))的形式,來讀取它:

須利用到一個StreamReader物件。StreamReader物件常用的宣告方式為:

StreamReader 變數名稱= new StreamReader (String "路徑" [ ,Encoding 編碼]);

可將讀取路徑上檔案的資料。

StreamReader 變數名稱= new StreamReader (FileStream FileStream物件[ ,Encoding 編碼]);

可將讀取FileStream物件之檔案的資料。

編碼,即是說以何種編碼讀取檔案內容文字,是個Encoding物件。Encoding物件的呼叫方法如下:

Encoding.ASCII:表示利用ASCII編碼來讀取檔案內容文字,ASCII編碼以一個byte作為一個字元。

Encoding.Unicode:表示利用Unicode編碼來讀取檔案內容文字。

Encoding.UTF8:表示利用UTF8編碼來讀取檔案內容文字,UTF8編碼一至四個byte作為一個字元(字元的byte數目乃是可變的)。這是預設值。

Encoding.GetEncoding("Big5")表示利用Big5編碼來讀取檔案內容文字。Big5用於為某些老舊的繁體中文檔案編碼。

(2-2) StreamReader物件常用的成員:

物件名稱.EndOfStream:一個bool。若為true,表示指標已在檔案的最末尾。若為false則否。此成員通常搭配while迴圈,來控制檔案的讀取內容。

(2-2) StreamReader物件常用的成員函式:

物件名稱.Read():回傳一個int(代表該字元之編碼的數值),並將指標往後進一個字元。若已讀至檔案末尾而無字元可讀,則回傳-1。可將該編碼數值轉換成字元,如:

char t = (char)物件名稱.Read();

則這個 t 就會是該字元。

物件名稱.Peek():回傳一個int(代表該字元之編碼的數值),不過並不移動指標。若已讀至檔案末尾而無字元可讀,則回傳-1。可將該編碼數值轉換成字元,和將物件名稱.Read()轉換為字元的方法相同。

物件名稱.ReadLine():回傳一個String。此函式在檔案內容中,以當前指標所在位置為出發點開始讀取,直到碰上第一個斷行字元為止。並將所讀取的內容文字回傳。

物件名稱.ReadToEnd():回傳一個String。此函式在檔案內容中,以當前指標所在位置為出發點開始讀取,直到檔案的末尾為止。並將所讀取的內容文字回傳。

物件名稱.Close():無回傳值。此函式會關閉該StreamReader物件。StreamReader物件在使用完後建議關閉,以免占用系統資源。

(3) 將檔案資料看做文字(char(字元)string(字串))的形式,來寫入它:

須利用到一個StreamWriter物件。StreamWriter物件最常用的宣告方式為:

StreamWriter 變數名稱= new StreamWriter(string "路徑" [,bool 添寫參數]);

可將資料寫入路徑上的檔案。其中,添寫參數若為true,表示寫入的方法是「添寫(保留原有資料,並從檔案末尾將新資料添寫進去)」而非「覆寫」,若為false則為覆寫。預設值為false

StreamWriter 變數名稱= new StreamWriter(FileStream FileStream物件);

可將資料寫入FileStream物件上的檔案。

(3-1) StreamWriter物件的常用成員函式有:

物件名稱.Write( 變數 ):無回傳值。其中,變數可以是字串、數字型態的變數、bool型態的變數、甚至可以是物件。此函式可將非字串型態的變數轉換成字串,並且寫入緩衝區。

物件名稱.WriteLine( 變數 ):無回傳值。此函式相當於在執行物件名稱.Write( 變數 )之後,再將斷行字元寫入緩衝區。

物件名稱.Flush():無回傳值。此函式可將緩衝區的資料寫入檔案。

物件名稱.Close():無回傳值。此函式可將緩衝區的資料寫入檔案,然後關閉檔案。StreamWriter物件在使用完後建議關閉,以免占用系統資源。

 

※ 簡單範例(檔案開頭已有加入using System.IO;這一行)

private void Form1_Load(object sender, EventArgs e)

{

      DirectoryInfo main_dir = new DirectoryInfo("main_dir");

      if (!main_dir.Exists)

      {

            main_dir.Create();

            FileInfo this_file = new FileInfo("main_dir\\file1.txt");

            FileStream this_file_stream = this_file.Create();

            StreamWriter this_file_writer = new StreamWriter(this_file_stream);

            this_file_writer.WriteLine("現在時間是:" + DateTime.Now);

            this_file_writer.Close();

      }

      else

      { textBox1.Text = "已存在main_dir資料夾!"; }

}

程式執行後,在該專案的專案名稱\bin\Debug」路徑下就會出現一個main_dir資料夾,其中有個file1.txt文字檔,其中就寫著程式執行時的時間。

 

 

上一篇:檔案的處理

下一篇:影像(image)

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

外部檔案的處理:

其利用到一個FileInfo物件。此物件代表著作業系統中某一個檔案路徑的相關資訊。該物件的宣告方法為:

FileInfo 物件名稱 = new FileInfo("路徑");

其中,路徑可為絕對路徑或相對路徑。

(1) FileInfo物件常用的成員:

物件名稱.FullName:一個string。代表該路徑絕對路徑形式。

物件名稱.Exists:一個bool。若為true,代表該路徑上已有檔案存在。若為false則代表該路徑上沒有徑物存在、或存在的徑物不是檔案。

物件名稱.CreationTime:一個DateTime物件。代表該路徑上之檔案創立的時間。若該路徑上之徑物是資料夾,也會顯示其創立的時間。但若該路徑上沒有徑物,則其時間會是1601/1/1 08:00:00

物件名稱.LastAccessTime:一個DateTime物件。代表該路徑上之檔案最近一次被存取的時間。若該路徑上之徑物是資料夾,也會顯示其最近一次被存取的時間。但若該路徑上沒有徑物,則其時間會是1601/1/1 08:00:00

物件名稱.Directory:一個DirectoryInfo物件。代表該路徑之父目錄的相關資訊。

物件名稱.Name:一個string。代表該路徑上之徑物名。

物件名稱.Length:一個long(長整數)。若該路徑上的徑物不是檔案,在存取此成員時會出錯。若該路徑上的徑物是檔案,則回傳該檔案的大小(Bytes為單位)

(2) FileInfo物件的常用成員函式:

物件名稱.Create():回傳一個FileStream物件。若路徑上沒有徑物,此函式會建立此檔案。而若路徑上的徑物是檔案,此函式會覆寫此檔案。無論是建立新檔還是覆寫舊檔,都會回傳檔案的FileStream物件。惟若此路徑上的徑物是資料夾,則此函式會出錯。

物件名稱.Delete():無回傳值。若路徑上的徑物是檔案,則此函式會刪除此檔案。而若路徑上的徑物不是檔案,則此函式會出錯。又若路徑上沒有徑物,則此函式不作用。

物件名稱.MoveTo(String "新路徑"):無回傳值。將該檔案從原本的路徑移至新路徑上。但若新路徑上已經有徑物存在,則此函式會出錯。

物件名稱.CopyTo(String "新路徑", [bool 覆寫參數]):回傳一個FileInfo物件。此函式將該檔案複製到新路徑上,並回傳該複製完之檔案的FileInfo。若覆寫參數true,則允許此函式覆寫新路徑上的徑物,若覆寫參數false,則在新路徑上已有徑物的情況下執行此函式會出錯。覆寫參數的預設值是false

物件名稱.Open(FileMode FileMode物件 [ ,FileAccess FileAccess物件]):可開啟此檔案,並回傳此檔案的FileStream物件。其中,FileMode物件是用來設定檔案的開啟模式;FileAccess物件物件是用來設定檔案所被允許的存取行為。

(-1) FileMode物件的呼叫方法:

FileMode.Open:路徑上若不存在檔案,會出錯。若存在檔案,則開啟該檔案。

FileMode.Create:路徑上若不存在檔案,則建立該檔案。若存在檔案,則覆寫該檔案。

FileMode.OpenOrCreate:路徑上若不存在檔案,則建立該檔案。若存在檔案,則保留該檔案並將它開啟。

FileMode.Truncate:路徑上若不存在檔案,會出錯。若存在檔案,則將檔案的內容文字全部刪除。

FileMode.Append:路徑上若不存在檔案,則建立該檔案。若存在檔案,則將指標移至該檔案的末尾(關於「指標」,請看4.

(-2) FileAccess物件的呼叫方法:

FileAccess.Read:以此方法開啟檔案之後,檔案只能讀不能寫。

FileAccess.Write:以此方法開啟檔案之後,檔案只能寫不能讀。

FileAccess.ReadWrite:以此方法開啟檔案之後,檔案可寫亦可讀。


 

 

 

上一篇:路徑的處理

下一篇:檔案內容的讀寫:streamreader、streamwriter、files

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

本章用詞:

徑物:代表一個路徑上的資料夾或檔案。

資料夾:和「目錄」是同一個意思。

 

路徑的處理:

其利用到一個Path類別(注意,是「Path類別」而不是「Path類別物件」)。其用法有(以下的路徑,可為絕對路徑、也可為相對路徑。而路徑上若不存在徑物,執行時也不會出現錯誤):

Path.GetFullPath(String "路徑"):回傳一個字串。乃是該路徑的絕對路徑形式。

Path.GetPathRoot(String "路徑"):回傳一個字串。乃是該路徑的根目錄所在。

Path.GetDirectoryName(String "路徑"):回傳一個字串。乃是該路徑上徑物,其所屬之資料夾的絕對路徑。

Path.GetFileName(String "路徑"):回傳一個字串。乃是該路徑上徑物的名稱。

Path.GetExtension(String "路徑"):回傳一個字串。乃是該路徑之徑物的副檔名。若該路徑上的徑物是資料夾,則回傳空字串。

Path.GetFileNameWithoutExtension(String "路徑"):回傳一個字串。乃是該路徑上徑物的名稱(不包含副檔名)

 

 

上一篇:資料夾的處理

下一篇:檔案的處理

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

 

 

(1) 其利用到一個DirectoryInfo物件。此物件代表著作業系統中某一個資料夾路徑的相關資訊。該物件的宣告方法為:

DirctoryInfo 物件名稱 = new DirwctoryInfo(String "路徑");

其中,路徑可為絕對路徑或相對路徑。若為相對路徑,則以該專案的執行檔所在之路徑為基準。這個該專案的執行檔所在之路徑」,通常為該專案資料夾下的:專案名稱\bin\Debug。例如某個專案名叫WindowsFormsApplication1,則這個「該專案的執行檔所在之路徑」就是該專案資料夾下的:WindowsFormsApplication1\bin\Debug

且在輸入相對路徑時,可用點號 . 來代表當前目錄,用兩個點號 .. 來代表當前目錄的父目錄。

  1. DirectoryInfo物件的常用成員:

物件名稱.FullName:一個string。代表該路徑絕對路徑形式。

物件名稱.Exists:一個bool。若為true,代表該路徑上已有資料夾存在。若為false則代表該路徑上沒有徑物存在、或存在的徑物不是資料夾。

物件名稱.CreationTime:一個DateTime物件。代表該路徑上之資料夾創立的時間。若該路徑上之徑物不是資料夾,也會顯示其創立的時間。但若該路徑上沒有徑物,則其時間會是1601/1/1 08:00:00

物件名稱.LastAccessTime:一個DateTime物件。代表該路徑上之資料夾最近一次被存取的時間。若該路徑上之徑物不是資料夾,也會顯示其最近一次被存取的時間。但若該路徑上沒有徑物,則其時間會是1601/1/1 08:00:00

物件名稱.Parent:一個DirectoryInfo物件。代表該路徑之父目錄的相關資訊。

物件名稱.Name:一個string。代表該路徑上之徑物名。

(2) DirectoryInfo物件的常用成員函式:

物件名稱.Create():無回傳值。若路徑上沒有徑物,此函式會在路徑上建立一個空的資料夾。而若路徑上有徑物,則此函式不作用。

物件名稱.CreatSubdirectory(String "名稱"):若路徑上沒有徑物、或路徑上的徑物是資料夾,則此函式會在路徑底下建立一個空的子資料夾,其名稱為名稱,並回傳一個將該子資料夾的DirectoryInfo物件。而若路徑上的徑物不是資料夾,則此函式會出錯。

物件名稱.Delete():無回傳值。若路徑上的徑物是資料夾,則此函式會刪除此資料夾。而若路徑上無徑物、或徑物不是資料夾,則此函式會出錯。

物件名稱.GetDirectories([String 檔名條件]):若路徑上的徑物是資料夾,則此函式會回傳一個DirectoryInfo物件的矩陣,而若路徑上無徑物、或徑物不是資料夾,則此函式會出錯。若沒寫檔名條件則回傳該路徑中所有子資料夾的相關資訊。若有寫檔名條件,則回傳符合該檔名條件所有子資料夾。檔名條件也支持萬用字元*的用法。例如,在dir1資料夾下有三個子資料夾dd1dd2hh。則:

物件名稱.GetDirectories()會回傳這三個子資料夾之DirectoryInfo物件的矩陣。

物件名稱.GetDirectories("dd1")回傳矩陣中的元素,就只有dd1這個子資料夾之DirectoryInfo物件。

物件名稱.GetDirectories("dd*")會回傳dd1dd2DirectoryInfo物件的矩陣。

物件名稱.GetFiles([String 檔名條件]):若路徑上的徑物是檔案,則此函式會回傳一個FileInfo物件的矩陣,代表該路徑中所有子檔案的相關資訊。而若路徑上無徑物、或徑物不是資料夾,則此函式會出錯。若沒寫檔名條件則回傳該路徑中所有子檔案的相關資訊。若有寫檔名條件,則回傳符合該檔名條件所有子檔案。檔名條件也支持萬用字元*的用法。

物件名稱.MoveTo(String "新路徑"):無回傳值。將該資料夾從原本的路徑移至新路徑上。但若新路徑上已經有徑物存在,則此函式會出錯。

(2) 資料夾的常用功能:

Directory.Exists("路徑"):檢查路徑上是否有資料夾。若有回傳true,否則回傳false。注意,若路徑上的徑物是檔案而非資料夾,也會回傳false

Directory.Delete("路徑", B):刪除該路徑上的資料夾。其中B是布林值,表示是否要遞迴式的刪除路徑資料夾裡面的子資料夾。若路徑上的資料夾內容不為空,則B要設為true,否則設為false。表示要若路徑上無資料夾,本函式會出錯。

Directory.CreateDirectory("路徑"):建立資料夾在路徑上。

 

 

 

上一篇:類別的繼承

下一篇:路徑的處理

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

類別的繼承

 

1. 子類別與父類別:

子類別(又稱「衍生類別」)和父類別(又稱「基礎類別」)這兩個名詞,隨著「繼承」這個動作的發生,而一起被定義。我們稱繼承者是子類別,被繼承者是父類別。「子類別繼承父類別」這句話,其意義是「父類別將自己的publicprotected的成員與成員函式傳遞給子類別,使子類別在宣告時不必宣告這些成員、成員函式,就能擁有他們」。

子類別的宣告式:

class 子類別名稱 : 父類別名稱

{

    類別成員宣告式

    類別成員函式宣告式

    類別建構式    

};

註:在子類別宣告式之內,可用this關鍵字來代表類別本身,而用base關鍵字來代表其父類別(可用base.成員base.成員函式名稱(參數一,參數二…)來呼叫父類別的成員與成員函式)。

再次強調,父類別中能夠被繼承的只有「publicprotected的成員與成員函式」。而父類別的建構式,就算其為public也不能被子類別繼承。子類別之建構式的寫法與一般類別不同(與其父類別的建構式有關),語法為:

存取修飾詞 子類別名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…) : base(父類別建構式參數一, 父類別建構式參數二…)

{

//函式內容(可以不需對賦類別建構式參數進行設定)

}

此語法之形式不易理解,可參考範例:

class person    

{

      public string name;

      public int age;

      public person(string n_, int a_) 

      { name = n_; age = a_; }

      public string self_introduction()

 { return "hi, I'm " + name + "," + age + "years old."; }

};

class boy : person    //boy是一個子類別,繼承了父類別person

{

      public int money;

      public boy(string n_, int a_, int money_) : base(n_, a_)

      { money = money_; }  //子類別建構式在此

};

boy b1 = new boy("Jack", 12, 200);  //子類別物件之宣告,仍按照子類別建構式的寫法

 

2. 在子類別重新定義父類別成員函式:

當子類別從父類別繼承了某個成員函式,但卻想改寫這個成員函式時(這個「改寫」,並不會影響父類別物件對該成員函式的使用,而是重新在子類別中定義該成員函式,以供子類別自己所用),有以下兩種方法:

(1) 子類別覆寫父類別的虛擬成員函式:

要成功使用這個方法的前提是:父類別中那個要被重新定義的成員函式,是個「虛擬函式」。虛擬函式的寫法需利用到virtual關鍵字,如下:

存取修飾詞 virtual 回傳資料型態 虛擬成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

{

//函式內容

}

而在子類別中,覆寫該虛擬函式需利用override關鍵字。語法如下:

存取修飾詞 override 回傳資料型態 虛擬成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

{

//函式內容

}

※ 範例如下:

class A

{ public virtual string intro(){ return "this is A";}};

class B : A

{ public override string intro(){ return "this is B"; }};

B b1 = new B();

textBox1.Text = b1.intro();   //顯示this is B

(2) 子類別成員函式直接取代父類別成員函式:

這種方法比較方便,直接在子類別中利用new關鍵字宣告欲取代的成員函式。語法為:

存取修飾詞 new 回傳資料型態 虛擬成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

{

//函式內容

}

※ 範例如下:

class A

{ public string intro(){ return "this is A";}};

class B : A

{ public new string intro(){ return "this is B"; }};

B b1 = new B();

textBox1.Text = b1.intro();   //顯示this is B

 

3. 父類別物件與子類別物件的轉換:

(1) 父類別物件,不能顯性轉換為子類別物件。

(2) 子類別物件,可以顯性轉換為父類別物件。只不過轉換之後,在該子類別內另行定義的成員和成員函式,將會消失。只有繼承父類別的成員和成員函式會保留下來。顯性轉換的方法為:

(父類別名稱)子類別物件名稱

如,今有一個person類別和一個man類別(man 類別繼承person類別,故person是父類別相對於man是子類別),一個man類別物件名為wang,則:

person jili_wang = (person)wang;

即可將wang轉成person類別後,儲存在jili_wang這個perosn類別物件裡。

 

4. 抽象類別與抽象成員函式:

所謂抽象成員函式」,指的是在該成員函式被宣告時,只有宣告其名稱、回傳資料形態、參數列,卻沒有宣告函式內容(函式內容不在類別本身中宣告,而是在該類別之衍生類別中再去覆寫)。而若某個類別擁有抽象成員函式,就稱其為「抽象類別」(抽象成員函式也只能在抽象類別中宣告)。抽象類別並不能被用來建立物件,而是專門被用來繼承的。這種用法,在較大、複雜的類別架構中,能使程式碼更為簡潔易讀。

抽象類別與抽象成員函式均用到關鍵字abstract。其宣告如下:

(1) 抽象類別的宣告:

abstract class 類別名稱

{

    類別成員宣告式

    類別成員函式宣告式

    類別建構式    

};

(2) 抽象成員函式的宣告:

abstract 存取修飾詞 回傳資料型態 成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

※ 註:抽象類別中可以沒有抽象成員函式,但有抽象成員函式的類別一定要宣告成抽象類別,否則程式執行時會出錯。

(3) 抽象成員函式的實作:

抽象成員函式的函式內容不在抽象類別本身中宣告,而是在該抽象類別之衍生類別中去覆寫。「為抽象成員函式寫入函式內容」這個動作,稱為對抽象成員函式的「實作(implement)」。

如以下範例:

abstract class person

{

      public string name;

      public int age;

      public person(string n_, int a_)

      { name = n_; age = a_; }

      abstract public string talk();       //抽象成員函式talk()在此   

};

class teacher : person  

{

      public teacher(string n_, int a_)

          : base(n_, a_){ }

      public override string talk()   //實作抽象成員函式talk()

      { return "Hi, My name is " + name + ", nice to meet you!"; }

};

class waiter : person

{

      public waiter(string n_, int a_)

          : base(n_, a_){  }

      public override string talk()    //實作抽象成員函式talk()

      { return "Welcome to our bar. Need something?"; }

};

由上範例可知,每個衍生類別對於抽象成員函式都有不同的實作方法,就如同生活中對於每種不同的人(person)進行交談(talk)時,他們的回話都不盡相同。這就是抽象成員函式在應用上的意義。

 

 

 

上一篇:類別物件的複製

下一篇:資料夾的處理

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

類別物件的複製:

(1) 設今有person類別如下:

class person

{

      public string name;

      public int age;

      public person(string n_, int a_)  //建構式在此

      { name = n_; age = a_; }

      public string self_introduction()

            { return "hi, I'm " + name + "," + age + "years old."; }

};

且已宣告一個person類別物件p1

person p1 = new person("weiwei", 18);

那麼要如何複製p1呢?

並不是只用person p2 = p1;就可複製p1,因為C#類別物件事實上只是個參考,並非實體。也就是說,p2p1參考同一個物件,所以改變p2的同時也會改變p1。證明如下:

            person p1 = new person("weiwei", 18);

            person p2 = p1;

            p2.name = "nunu";

            richTextBox1.Text = p1.name.ToString();

則程式執行完成後,richTextBox1.Text之值會是nunu

(2) 要在C#中執行真正的複製,也就是複製一個與原先物件有相同成員值、成員函數,但互相獨立、彼此互不影響的物件,必須用「深複製(deep copy)」方法。也就是說在類別中自寫一個函式,可回傳一個相同類別物件,而此類別物件與本物件一模一樣。如在person類別中,寫下deep_copy()函式

                  public person deep_copy()

            {

                person new_person = new person(this.name, this.age);

                return new_person;

            }

然後:

            person p1 = new person("weiwei", 18);

            person p2 = p1.deep_copy();

            p2.name = "nunu";

            richTextBox1.Text = p1.name.ToString();

則程式執行完成後,richTextBox1.Text之值還是weiwei

(3) 深複製並非只有這麼簡單,若碰上更複雜的類別,那就會變得更麻煩。如在上例中再加上一個kingdom類別:

class kingdom

{

public person king;

public person queen;

public List<person> worker = new List<person>();

public string name;

public string history;

public int money;

public kingdom(string name_)

{ name = name_; }           

}

那麼在寫深複製函式之前,要先搞清楚哪些成員是類別物件,要先為這些成員寫深複製函式才行。kingdom類別的深複製函式如下:

            public kingdom deep_copy()

            {

                kingdom new_k = new kingdom(this.name);

                new_k.king = this.king.deep_copy();

                new_k.queen = this.queen.deep_copy();

                new_k.worker = this.worker.ToList();

                new_k.history=this.history;

                new_k.money = this.money;

                return new_k;

            }

然後利用下列程式碼測試:

            kingdom k1 = new kingdom("AAA");

            k1.king = new person("king.AAA", 50);

            k1.queen = new person("queen.AAA", 40);

            k1.worker.Add(new person("w1.AAA", 20));

            k1.worker.Add(new person("w2.AAA", 25));

            k1.history = "AAA's history";

            k1.money = 100;

 

            kingdom k2 = k1.deep_copy();

            k2.king = new person("king.BBB", 50);

            k2.queen = new person("queen.BBB", 40);

            k2.worker.Add(new person("w1.BBB", 20));

            k2.worker.Add(new person("w2.BBB", 25));

            k2.history = "BBB's history";

            k2.money = 200;

 

            richTextBox1.Text +=

            "k1:king = " + k1.king.name + "\r\n" +

            "k1:queen = " + k1.queen.name + "\r\n" +

            "k1:worker = ";

            for (int i=0;i<k1.worker.Count;i++)

            {

                richTextBox1.Text +=k1.worker[i].name+",";

            }

            richTextBox1.Text += "\r\n" +

            "k1:history = " + k1.history + "\r\n" +

            "k1:money = " + k1.money + "\r\n";

則程式執行完成後,richTextBox1.Text之值為:

k1:king = king.AAA

k1:queen = queen.AAA

k1:worker = w1.AAA,w2.AAA,

k1:history = AAA's history

k1:money = 100

這代表深複製函式的成功。

 

 

 

上一篇:靜態成員與靜態成員函式

下一篇:類別的繼承

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

(1) 靜態成員:

所謂靜態成員,是指這個成員之值為所有同類別之物件所「共享」。靜態成員在所有類別物件裡的值都一樣,若經更改,則此靜態成員的值在所有同類別物件中也都會更改。靜態成員的宣告式,比之一般成員的宣告式,多了static關鍵字,其語法為:

存取修飾詞 static 靜態成員資料型態 靜態成員名稱 = ;

其中,存取修飾詞的寫法與類別成員宣告式中的存取修飾詞寫法相同。

靜態成員不僅屬於特定一個物件,而是屬於該類別本身。在類別外存取該類別之靜態成員的方法為(需先確定該靜態成員是public)

類別名稱.靜態成員名稱=;

範例:

class person

{

      public static int number_of_person=0;   //這就是靜態成員

      public string name;

      public int age;

      public person(string n_, int a_)

      { name = n_; age = a_; number_of_person++; }  //每宣告一次person物件,number_of_person靜態成員就會增加1

};

person p1 = new person("weiwei", 18);

person p2 = new person("nunu", 20);

textBox1.Text = person.number_of_person.ToString();   //再次提醒,靜態成員的呼叫不是類別物件名稱.靜態成員名稱,而是類別名稱.靜態成員名稱

執行後顯示:2

(2) 靜態成員函式:

靜態成員函式,只能對靜態成員進行操作、不能對一般成員進行操作。順便一提,一般的非靜態成員函式,對靜態成員、非靜態成員都可以操作。靜態成員函式的宣告式,比之一般成員函式的宣告式,多了static關鍵字,其語法為:

存取修飾詞 static 回傳資料型態 成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

{

//函式內容

}

其中,存取修飾詞的寫法與類別成員宣告式中的存取修飾詞寫法相同。

靜態成員函式不僅屬於特定一個物件,而是屬於該類別本身。在類別外存取該類別之靜態成員函式的方法為(需先確定該靜態成員是public)

類別名稱.靜態成員函式名稱(參數一,參數二,參數三…);

 

 

上一篇:類別的「成員」與「屬性」

下一篇:類別物件的複製

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

類別的成員屬性

類別成員」的存取是很直接的,不會另做任何的修飾。如2.(2)中的p1.age=20;這一行,就直接將20存入p1.age這個成員中。而age這個成員代表的是該person的年齡,不應為負數,故我們須防止p1.age=-10;這種不合理的情況發生。雖說若由程式設計者本身存取屬性,人腦能避免做出這種不合理的設定,但有時我們是由電腦去計算屬性的值,就難免有不合理的狀況。故在存取成員時,須對另作修飾。有做這種修飾的成員,我們稱呼他為屬性」。

如前所述,類別成員宣告式的寫法為:

存取修飾詞 成員資料型態 成員名稱 = ;

而類別屬性宣告式的寫法就是:

存取修飾詞 屬性資料型態 屬性名稱

{

          get

          {

                   //該屬性在被讀取時的修飾

                   return 變數名稱;

}

set

{

          //該屬性在存取時的修飾

          //需以關鍵字value來代表存入的值

}

}

註:如果不寫set{}、只有寫get{},那該屬性就會是「惟讀的(read-only)」。如果不寫get{}、只有寫set{},那該屬性就會是「惟寫的(write-only)」。

範例:如將2.(1)person類別改成如下:

class person

{

    public string name;

    public int _age_;

    public int age 

    {

          get { return _age_; }

          set {

                   if (value < 0) { _age_ = 0; }

                   else { _age_ = value; }

             }

    }

    public person(string n_, int a_) 

    { name = n_; age = a_; }

    public string self_introduction()

    { return "hi, I'm " + name + "," + age + "years old."; }

};

person p1 = new person("weiwei", 18);

p1.age = -20;  

textBox1.Text = p1.age.ToString()+" years old.";  //顯示:0 years old.

說明一:就算p1.age = -20;,在呼叫p1.age時,其結果還是變成0。避免了歲數為負數的不合理情況。此法對建構式賦值亦管用。

說明二:在類別內部存取時,是存取_age_屬性。而在類別外部存取時,就是存取age成員。而_age_是筆者自訂的變數名,此變數名在字面上並不需要和age有任何的關係,取成_age_只是為了方便辨識而已。恐人誤會,特此提及。

 

 

上一篇:類別物件的宣告與使用

下一篇:靜態成員與靜態成員函式

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

類別物件的宣告與使用:

(1) 要在該類別外宣告類別物件,需使用類別建構式(需先確定該類別建構式的存取修飾詞public)。若類別建構式為:

public 類別名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

{

//函式內容

}

則該類別變數的宣告式,就是:

類別名稱 類別物件名稱 = new 類別名稱(參數一之值, 參數二之值…); 

若程式設計者沒有設定類別建構式,則C#會預設一個類別建構式,為:

public void類別名稱(){ }

則該類別變數的宣告式,就是:

類別名稱 類別物件名稱 = new 類別名稱();

範例如下:

設有一類別,名為person,宣告式為:

class person

{

      public string name;

      public int age;

      public person(string n_, int a_)  //建構式在此

      { name = n_; age = a_; }

      public string self_introduction()

            { return "hi, I'm " + name + "," + age + "years old."; }

};

則該類別變數的宣告式,例如:

person p1 = new person("weiwei", 18);

(2) 要在該類別外使用該類別物件的成員、成員函式(需先確定該這些成員、成員函式的存取修飾詞public),需先宣告該類別物件。語法為

類別物件名稱.成員名稱; 類別物件名稱.成員函式名稱(參數一,參數二…);

2.(1)person類別為範例:

person p1 = new person("weiwei", 18);  //先宣告類別物件

p1.age=20;    //設定該類別物件的成員

string S = p1.self_introduction();    //呼叫該類別物件的成員函式

 

 

上一篇:類別的宣告

下一篇:類別的「成員」與「屬性」

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

類別的宣告:

一個類別中,通常會含有「類別成員」、「類別成員函式」、「類別建構式」,三者皆可以有任意個。若三者皆沒設定,則這種類別稱為「空類別」。

(1) 整體宣告:

class 類別名稱

{

    類別成員宣告式

    類別成員函式宣告式

    類別建構式    

};

(1-1) 類別成員宣告式的寫法為:

存取修飾詞 成員資料型態 成員名稱 = ;

其中,存取修飾詞代表著該成員在被本類別外的物件存取時受到怎樣的限制。

存取修飾詞有三種寫法,如下:

public:表示此成員可以被任何類別、類別物件所存取。

protected:表示此成員只能被該類別本身、和該類別的衍生類別存取。無法被該類別物件、其他類別、其他類別物件存取。

private:表示此成員只能被該類別本身存取。

列表如下(代表可存取、×代表不可存取)

存取修飾詞

本身類別

本身類別物件

衍生類別

衍生類別物件

其他類別

其他類別物件

public

protected

×

×

×

×

private

×

×

×

×

×

若不寫存取修飾詞,則預設該成員為private

(1-2) 類別成員函式宣告式的寫法為:

存取修飾詞 回傳資料型態 成員函式名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

{

//函式內容

}

其中,存取修飾詞的寫法與類別成員宣告式中的存取修飾詞寫法相同。

(1-3) 類別建構式像是一個函式,使用者可用此建構式來宣告該類別的物件。其寫法為:

存取修飾詞 類別名稱(參數資料型態一 參數一, 參數資料型態二, 參數二…)

{

//函式內容

}

其中,存取修飾詞的寫法與類別成員宣告式中的存取修飾詞寫法相同。若欲在類別本身之外建立該類別物件,則存取修飾詞應寫為public

註一:若程式設計者沒有設定類別建構式,則C#會預設一個類別建構式,為:

public void類別名稱(){ }

註二:在類別宣告式之內,可用this關鍵字,來代表類別本身。

參考:在類別中,也可以宣告解構式,不過這並不常用。解構的的寫法為:

~類別名稱() 

{ //解構式內容 }

解構式不使用參數和存取修飾詞。其功用,通常是由系統在編譯時自行判斷該物件是否還需要使用,若不需要,就依照解構式將其從記憶體中拿出,免得佔用記憶體空間。是故,解構式通常不需由程式設計者去呼叫,系統自會判斷何時該解構。若程式設計者要強制在類別外執行解構式,可用:

System.GC.Collect();

不過若是使用時機有誤,會造成記憶體效能的損失,切勿輕易使用。

(2) 分開宣告:

所謂類別的分開宣告,並不像上述的整體宣告一樣,把所有的成員、成員函式、建構式都寫在同一個宣告式中,而是分開寫在幾個不同的宣告式中。這種宣告法在類別裡的成員太多、種類太雜時,比較用的上。可以利用關鍵字partial以達成分開宣告。

以下為一個名為person的類別,其整體宣告」的寫法

class person  //這是第一個宣告式

{

      public string name;

      public int age;

      public person(string n_, int a_)  

      { name = n_; age = a_; }

      public string self_introduction()

            { return "hi, I'm " + name + "," + age + "years old."; }

};

與一個分開宣告」的寫法

partial class person  //這是第一個宣告式

{

        public string name;

        public person(string n_, int a_)

        { name = n_; age = a_; }

};

partial class person  //這是第二個宣告式

{ public int age;};

partial class person  //這是第三個宣告式

{ public string self_introduction(){ return "hi, I'm " + name + "," + age + "years old."; }};

此兩者雖然在寫法上有別,但其效果和類別物件的使用方法是完全一樣的。

要注意,分開宣告時,每一個宣告式之前多了一個partial關鍵字。

 

 

上一篇:遞迴函式

下一篇:類別物件的宣告與使用

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

SortedList的用法比ArrayList更具有彈性,不僅其長度是「可變的」、陣列清單不須宣告資料形態,亦可自行設定搜尋之索引。索引可以是任何物件。要注意的是,「索引」和「序數」是兩個不同的概念。SortedList同時使用索引和序數來定位元素。索引由使用者自行設定,至於序數則是由系統設定。

重要:要使用SortedList,必須在程式開頭處加上這一行:

using System.Collections;

1. SortedList的宣告:

SortedList B= new SortedList();

在宣告之後,這個SortedList的長度是0。要使用Add方法來為SortedList加入元素,如:

SortedList名稱.Add(索引,);    //其中,索引一樣可以是任何物件。

之後,才能對清單的值進行呼叫與重設:

清單名稱[索引];    //呼叫該索引之元素的值

清單名稱[索引]=;    //重設該索引之元素的值為

註:回傳的是以Object的資料型態回傳,並非以原先設定時的型態回傳。

例如:

SortedList A= new SortedList();

A.Add("one","");

A.Add("two","");

A.Add("three", Color.Red);

textBox1.Text = A["one"].ToString();  //就算在設定A["one"]時,A["one"]的值是個string,其回傳的仍是一個Object的資料型態,故仍須轉換回string

是某類別物件,則在取值時應以該類別的資料型態來解碼該,即如下:

類別名稱 變數名稱=(類別名稱) SortedList名稱["索引"];

 

2. SortedList所常用的成員及方法:

(1) 常用的成員:

SortedList名稱.Count:這是一個int,代表該SortedList的長度(元素數目)

(2) 常用的成員函式:

SortedList名稱.Add(索引,):可將該索引加入此SortedList。其中,索引可以是任何物件。

SortedList名稱.Clear():把這個SortedList中所有的元素都刪除。這樣一來,SortedList的長度會變成0

SortedList名稱.Remove(索引):無回傳值。可將該SortedList之索引為索引的元素刪除。

SortedList名稱.GetByIndex(N)回傳該SortedList中,序數為N之元素的值。

SortedList名稱. GetKey(N):回傳該SortedList中,序數為N之元素的索引。

SortedList名稱.RemoveAt(N):無回傳值。刪除該SortedList中,序數N的元素。而其後面的元素往前順移排列。

SortedList.IndexOfKey(索引):回傳該所引的序數,其值從0開始算起。若這個SortedList中沒有該索引,則為回傳-1

 

 

 

 

 

上一篇:arraylist

下一篇:函式

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

陣列清單的長度是「可變的」,且陣列清單不須宣告資料形態:任何資料形態的變數或物件都可以加入同一個陣列清單。

重要:要使用陣列清單,必須在程式開頭處加上這一行:

using System.Collections;

1. 陣列清單的宣告:

ArrayList 陣列清單名稱 = new ArrayList();

在宣告陣列清單後,這個陣列清單的長度是0,也就是說沒有任何元素。要使用Add方法來為清單加入元素,如:

陣列清單名稱.Add();    //這方法會將給加入陣列清單的末尾成為陣列清單中目前最後一個元素

之後,才能對陣列清單的值進行呼叫與重設:

陣列清單名稱[序數];    //呼叫該序數之元素的值

陣列清單名稱[序數]=;    //重設該序數之元素的值為

例如:

ArrayList A =new ArrayList();

A.Add("d");

A.Add(1);

A.Add(Color.FromArgb(0, 0, 0));

 

2. 陣列清單所常用的成員及方法:

(1) 常用的成員:

陣列清單名稱.Count:這是一個int,代表該陣列清單的長度(元素數目)

(2) 常用的成員函式:

陣列清單名稱.Add(變數):把這個變數給加入到陣列清單之末尾,成為陣列清單目前的最後一個元素。

陣列清單名稱.Clear():把這個陣列清單中所有的元素都刪除。這樣一來,陣列清單的長度會變成0

陣列清單名稱.Insert(N,):將插入該陣列清單中序數N的位置。原本序數N其及之後的元素,都會往後移順移排列。

陣列清單名稱.Remove():該陣列清單中若有元素的值為,就將此元素刪除,並回傳true,而後面的元素往前順移排列。否則回傳false

注意,該陣列清單中若有兩個以上的元素的值為,此方法只會移除序數最小的那個元素。

陣列清單名稱.RemoveAt(N):刪除該陣列清單中,序數N的元素。而其後面的元素往前順移排列。

陣列清單名稱.Reverse(N,L):將該陣列清單中,自序數N開始連續共L個元素(包含序數N所對應的元素),給反向排列。

陣列清單名稱.Sort():將該陣列清單中的元素進行遞增排序。這只在該陣列清單中的元素都是同一種資料形態時才管用。若其元素之資料形態不完全相同,此函式會出錯。

陣列清單名稱.IndexOf():回傳一個int。搜尋該陣列清單中,是否有哪個元素的值是。若有則回傳其序數,若無則回傳-1。若有兩個以上元素的值是,則回傳序數最小者的序數。

 

 

上一篇:list

下一篇:sortedlist

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

清單不像陣列一樣要宣告長度,清單的長度是「可變的」。

1. 清單的宣告:

(1) 不宣告初始值的宣告方式:

List<資料型態> 清單名稱 = new List<資料型態>();

在宣告清單後,這個清單的長度是0,也就是說沒有任何元素。要使用Add方法來為清單加入元素,如:

清單名稱.Add();    //這方法會將給加入清單的末尾成為清單中目前最後一個元素

之後,才能對清單的值進行呼叫與重設:

清單名稱[序數];    //呼叫該序數之元素的值

清單名稱[序數]=;    //重設該序數之元素的值為

例如:

List<int> A = new List<int>();

A.Add(3);

A.Add(5);

A.Add(7);

註:二維清單宣告方式:

List<List<資料型態>> 清單名稱= new List<List<資料型態>>();

(2) 宣告初始值的宣告方式:

List<資料型態> 清單名稱 = new List<資料型態>{ 值一, 值二, 值三… };

範例如:

List<int> scores = new List<int>{ 76, 23, 56,81,99 };

 

 

2. 清單所常用的成員及方法:

(1) 常用的成員:

清單名稱.Count:這是一個int,代表該清單的長度(元素數目)

(2) 常用的成員函式:

清單名稱.Add(變數):把這個變數給加入道清單之末尾,成為清單目前的最後一個元素。

清單名稱.AddRange(其他清單):把其他清單中的元素依序加入到清單之末尾。

清單名稱.Last():回傳該清單中的最後一個元素。

清單名稱.Clear():把這個清單中所有的元素都刪除。這樣一來,清單的長度會變成0

清單名稱.Insert(N,):將插入該清單中序數N的位置。原本序數N其及之後的元素,都會往後移順移排列。

清單名稱.Remove():該清單中若有元素的值為,就將此元素刪除,並回傳true,而後面的元素往前順移排列。否則回傳false

注意,該清單中若有兩個以上的元素的值為,此方法只會移除序數最小的那個元素。

清單名稱.RemoveAt(N):刪除該清單中,序數N的元素。而其後面的元素往前順移排列。

清單名稱.Reverse(N,L):將該清單中,自序數N開始連續共L個元素(包含序數N所對應的元素),給反向排列。

清單名稱.Sort():將該清單中的元素進行遞增排序。

清單名稱.Sum():若該清單的資料形態是int,則回傳一個int。若該清單的資料形態是double,則回傳一個double。代表該清單中所有元素的加總。

若該清單的資料形態是string或其他,則有可能發生錯誤。

清單名稱.GetType():回傳一個型態為System.Type的變數,表示該清單的資料型態。

清單名稱.IndexOf():回傳一個int。搜尋該清單中,是否有哪個元素的值是。若有則回傳其序數,若無則回傳-1。若有兩個以上元素的值是,則回傳序數最小者的序數。

清單名稱.GetRange(a,N):回傳該清單中,自第a個元素起,共N個元素(包含第a個元素)。所回傳的資料型態等於該清單本身的資料型態。要注意的是,回傳的清單僅只是一個參考位置,若該回傳的清單其中的元素遭到改變,則原本清單中的元素一樣會遭到改變。如以下程式碼:

public class person

{

    public int age;

    public string name;

    public person(int a, string n){ age = a; name = n; }

}

private void Form1_Load(object sender, EventArgs e)

{

    List<person> ps = new List<person>();

    person p1 = new person(10, ""); person p2 = new person(12, "");

    ps.Add(p1); ps.Add(p2);

    List<person> new_ps = ps.GetRange(0, 1);

    new_ps[0].age = 11;

    richTextBox1.Text = ps[0].age+"\r\n";

}

結果顯示:11

 

3. 清單的複製:

清單宣告式:List<資料型態> 清單名稱 = new List<資料型態>(); 之中,清單名稱實際上不是一個變數實體、而是一個指標。所以,若有以下程式碼:

List<資料型態> 清單名稱一 = new List<資料型態>();

List<資料型態> 清單名稱二 = 清單名稱一;

清單名稱一清單名稱二是指向同一個實體。例如:

List<int> A = new List<int>();

A.Add(5);

List<int> B = A;

B[0] = 10;

textBox1.Text += A[0].ToString();

則文字方塊中顯示出來的是10而非5

(1) 而若要將清單名稱一所指向的實體複製,然後讓清單名稱二指向該複製後的實體,要這樣寫:

List<資料型態> 清單名稱二 = 清單名稱一.ToList();

例如:

List<int> A = new List<int>();

A.Add(5);

List<int> B = A.ToList();

B[0] = 10;

textBox1.Text += A[0].ToString();

則文字方塊中顯示出來的就會是5了。

注意:上述方法不能用在二維清單及多維清單上。若用在二維清單上如:

List<List<int>> A = new List<List<int>>();

for (int i = 0; i <= 1; i++)

{

List<int> tmp = new List<int>();

for (int j = 0; j <= 1; j++)

{ tmp.Add(1); }   //將二維清單A的四個元素都設為1

A.Add(tmp);

}

 

List<List<int>> B = A.ToList();

for (int i = 0; i <= 1; i++)

{

for (int j = 0; j <= 1; j++)

{ B[i][j]=2; }    //將二維清單B的四個元素都設為2

}

textBox1.Text += A[0][0].ToString()+","+A[0][1].ToString()+","+A[1][0].ToString()+","+A[1][1].ToString();

則文字方塊中顯示出來的卻會是2,2,2,2了。這表示對B進行操作,卻同時也改變了A

若要複製二維清單,應逐項複製二維清單底下的一維清單,範例如下:

List<List<int>> A = new List<List<int>>();

for (int i = 0; i <= 1; i++)

{

List<int> tmp = new List<int>();

for (int j = 0; j <= 1; j++)

{ tmp.Add(1); }  //將二維清單A的四個元素都設為1

A.Add(tmp);

}

                            

List<List<int>> B = new List<List<int>>();

for (int i = 0; i <= 1; i++)

{

B.Add( A[i].ToList()); }  //逐項複製A的一維清單到B的一維清單

}

 

for (int i = 0; i <= 1; i++)

{

for (int j = 0; j <= 1; j++)

B[i][j] = 2; }    //將二維清單B的四個元素都設為2

}

textBox1.Text += A[0][0].ToString()+","+A[0][1].ToString()+","+A[1][0].ToString()+","+A[1][1].ToString();

則文字方塊中顯示出來的就會是1,1,1,1了。

 

4. 清單的排序:

(1) 清單名稱.Sort()可將該清單中的元素進行遞增排序:

若該清單的元素資料型態是數字,比如intshortfloatdouble…等,那麼這個函式可將元素由小排到大。

若該清單的元素資料型態是char,那麼此函式會依照元素的ASCII碼大小將之由小排到大。如:

List<char> ss = new List<char>() { 'a','g','e','t','b','z','c' };

ss.Sort();

則排序後清單呈現:{'a', 'b' , 'c' , 'e' , 'g' , 't' , 'z' }

若該清單的元素資料型態是string,那麼此函式會依照元素中第一個字元的ASCII碼大小將之由小排到大。若第一個字元的ASCII碼相同,則再比第二個字元的ASCII碼;若第二個字元的ASCII碼相同,則再比第三個字元的ASCII。如:

List<string> ss = new List<string>() { "sssabb", "abc", "abb", "bcb", "bca","a","b" };

ss.Sort();

則排序後清單呈現:{ "a", "abb", "abc", "b", "bca", "bcb", "sssabb" }

(2) 若清單中元素的資料型態是類別,則排序依據就應該是類別中某成員的大小,甚至更複雜的情況下,也可能是類別中某些成員經過某種演算法演算後的大小。此時可利用清單名稱.Sort(delegate),關於delegate,可參考「函式」教學。

在進行範例前先定義一個類別:

public class person

{

public string name;

public int age;

public double height;

public int money;

public person(string name_, int age_, double h, int m)

{ name = name_; age = age_; height = h; money = m; }

}

List<person> ps = new List<person>();

ps.Add(new person("", 18, 1.66, 5000));

ps.Add(new person("", 22, 1.76, 6000));

ps.Add(new person("", 10, 1.52, 2000));

ps.Add(new person("", 30, 1.63, 5500));

ps.Add(new person("", 21, 1.70, 1000));

ps.Add(new person("", 15, 1.32, 7000));

接著,要對一個ps進行排序。假設,排序的依據是personage大小。

※ 範例(2-1):利用一個匿名函式(delegate),製作出一種「比較標準」來比較兩個person(p1,p2)之間的順序。若p1p2大則此函式回傳1,若p1=p2則此回傳0,若p1p2小則回傳-1

由於排序的依據是personage大小,故該匿名函式的內容就是去比較personage大小。CompareTo函式是數字資料型態(intshortfloatdouble…)所有的成員函式,用法例如:

double a=1.0, b=1.5;

情況

a.CompareTo(b)的回傳值

a>b

1

a==b

0

a<b

-1

故,可利用CompareTo函式來建立匿名函式,排序的範例如:

ps.Sort(delegate(person p1, person p2) { return p1.age.CompareTo(p2.age); });

for (int i = 0; i < ps.Count; i++)  // 顯示結果

{richTextBox1.Text += ps[i].name + ", "+"age="+ps[i].age+"\r\n";}

執行後,richtextbox中顯示:

, age=10

, age=15

, age=18

, age=21

, age=22

, age=30

表示ps已依據age之大小由小排到大。若要改成由大排到小,可以用ps.Reverse()函式。若要更改排序依據(比如改成以height大小來排序),可將delegate中的

delegate(person p1, person p2) { return p1.age.CompareTo(p2.age); }

改成

delegate(person p1, person p2) { return p1.height.CompareTo(p2. height); }

要注意的是,delegate中的參數是person類別,而ps清單中的元素也是person類別。這表示,delegate中的參數,其變數型態,必須同於清單中元素的變數型態。

※ 範例(2-2):使用定義的函式來建立「比較標準」:

public static int person_comprasion(person p1, person p2)

{return p1.age.CompareTo(p2.age); }

 

ps.Sort(person_comprasion);  // 利用person_comprasion函式來排序

for (int i = 0; i < ps.Count; i++)  // 顯示結果

{richTextBox1.Text += ps[i].name + ", "+"age="+ps[i].age+"\r\n";}

執行後,richtextbox中顯示:

, age=10

, age=15

, age=18

, age=21

, age=22

, age=30

(3) 排序ps中的index

有時,程式設計師只想知道排序後的結果,但不想改變ps中的順序(也許這是因為ps原本的順序已被記錄下來以供其他用途,一旦更改後將會使該用途出錯),此時可以另立一個List<int> indexs代表ps中元素的index,使用以下範例將indexs排序,即可不影響ps中的順序:

List<int> indexs = new List<int>();

for (int i = 0; i < ps.Count; i++) { indexs.Add(i); }

indexs.Sort(delegate(int i1, int i2) { return ps[i1].age.CompareTo(ps[i2].age); });

for (int i = 0; i < indexs.Count; i++)   // 顯示結果

{ richTextBox1.Text += "index = " + indexs[i] + ", " + ps[indexs[i]].name + ", " + "age=" + ps[indexs[i]].age + "\r\n"; }

執行後,richtextbox中顯示:

index = 2, , age=10

index = 5, , age=15

index = 0, , age=18

index = 4, , age=21

index = 1, , age=22

index = 3, , age=30

 

 

上一篇:array

下一篇:arraylist

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

1. 陣列的宣告:

(1) 宣告陣列時,也順便宣告元素初始值:

資料型態[] 陣列名稱 = {值一,值二,值三… };

如:

int[] A = {3,5,2};

(2) 不宣告初始值,但宣告陣列長度:

資料型態[] 陣列名稱 = new 資料型態[N];

如:

double[] A = new double[100];

(3) 分段式宣告:

資料型態[] 陣列名稱;    //先宣告陣列

陣列名稱 = new 資料型態[N];    //再宣告陣列長度,令陣列長度為N

陣列名稱[序數] = ;    //再逐一宣告值

如:

string[] A;

A=new string [3];

A[0] = "dd";

A[1] = "ff";

A[2] = "gg";

註:在宣告陣列長度為N時,會自動指派N個元素給陣列。若該陣列的資料型別是intdouble,則這N個變數的初始值就是0;若該陣列的資料型別是string,則這N個變數的初始值就是空字串;若該陣列的資料型別是bool,則這N個變數的初始值就是False

 

2. 多維陣列的宣告與使用:

(1) 二維陣列:

(1-1) 二維陣列的宣告:

(1-1-1) 不進行初始化的宣告:

資料型態[,] 陣列名稱 = new 資料型態[N1,N2];

其中,N1N2是整數,代表第一階的陣列(也就是該陣列名稱所代表的陣列本身)N1個子陣列(也就是N1個第二階陣列),而第二階陣列有N2個元素。整個陣列共有N1*N2個元素。這N1*N2個元素的初始值會被自動設定:若該陣列的資料型別是int,則所有元素初始值就都是0;若該陣列的資料型別是string,則所有元素初始值就都是空字串;若該陣列的資料型別是bool,則所有元素初始值就都是False

(1-1-2) 進行初始化的宣告:

資料型態[,] 陣列名稱 = new 資料型態{子陣列一, 子陣列二, 子陣列三…};

範例如:

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

當然,為了易讀,也可寫成:

int [,] array_2D=new int[,]

{

{1,2},

{3,4},

{5,6}

};

(1-2) 二維陣列元素值的設定與呼叫:

陣列名稱[序數一,序數二];     //元素值的呼叫

陣列名稱[序數一,序數二] = ;     //元素值的設定

如:

string[,] array_2D = new string[2,3];

array_2D[0, 0] = "AAA";

array_2D[0, 1] = "BBB";

array_2D[0, 2] = "CCC";

array_2D[1, 0] = "aaa";

array_2D[1, 1] = "bbb";

array_2D[1, 2] = "ccc";

(1-3) 二維陣列之長度、與其子陣列的長度:

(1-3-1) 陣列名稱.Length:此成員回傳整個陣列的元素個數。例如有個陣列宣告如為:int [,] array_2D=new int[,]{{1,2},{3,4},{5,6}};,則其長度就是2*3=6

(1-3-2) 陣列名稱.GetLength(K):其中,K是非負整數,從0算起。此方法回傳第K層子陣列的數目。例如有個陣列宣告如為:int [,] array_2D=new int[,]{{1,2},{3,4},{5,6}};,則GetLength(0)會回傳3GetLength(1)會回傳2GetLength(2)就會出錯,因該陣列只有二維,也就是說只有第0層和第1層。

(2) 多維陣列(宣告與使用的方法,和二維陣列同理)

(2-1) 多維陣列的宣告:

資料型態[,, …] 陣列名稱 = new 資料型態[N1,N2,N3…];

其中,[,, …]表示,若是x維陣列,則中括號[]中就要有x-1個逗號 ,

其中,[N1,N2,N3…]表示,若是x維陣列,則中括號[]中就要有xN

同樣,宣告完的陣列也會被賦予初始值。

如以下是宣告一個三維陣列:

int[,,] A = new int[2,3,1];

(2-2) 多維陣列元素值的設定與呼叫:

陣列名稱[序數一,序數二,序數三…];     //元素值的呼叫

陣列名稱[序數一,序數二,序數三…] = ;     //元素值的設定

(2-3) 多維陣列的複製:

利用Array.copy(多維陣列甲,多維陣列乙,N)方法,可將多維陣列甲中的前N個元素複製到多維陣列乙中。且複製完後,對多維陣列乙的操作不會影響多維陣列甲。範例如:

int[,] AA = new int[1000, 1000];

for (int i = 0; i < 1000; i++)

{

for (int j = 0; j < 1000; j++)

{ AA[i,j] = 1; }

}

 

int[,] BB = new int[1000, 1000];

Array.Copy(AA, BB, 1000*1000); 

(3) 不定長度多維陣列:

此種陣列,其每個子陣列的長度都可以不相同。

(3-1) 宣告之範例如下:

double[][][] Asss = new double[10][][];

for (int i1 = 0; i1 < 10; i1++)

{

double[][] Ass = new double[2*i1][];

for (int i2 = 0; i2 < 2*i1; i2++)

{

double[] As = new double[2*i2+i1];

for (int i3 = 0; i3 < 2*i2+i1; i3++)

{ As[i3] = i3*i2-5*i1;}

Ass[i2] = As;

}

Asss[i1] = Ass;

}

(3-2) 不定長度多維陣列元素值的設定與呼叫:

陣列名稱[序數一][序數二][序數三]…;     //元素值的呼叫

陣列名稱[序數一][序數二][序數三]…= ;     //元素值的設定

 

 

3. 陣列所能使用的成員及方法:

C#中的陣列是繼承自System.Array類別,此類別提供了一些成員和方法供陣列使用,如下:

(1) 常用的成員:

陣列名稱.IsFixedSize:其值的型態為bool。若其值為True,表示該陣列的長度已被宣告,否則其值為False

陣列名稱.IsReadOnly:其值的型態為bool。若其值為True,表示該陣列是唯獨的,否則其值為False

陣列名稱.Length:其值的型態為int。代表該陣列的長度。

陣列名稱.Rank:其值的型態為int。代表該陣列的維度。

(2) 常用的方法:

陣列名稱.GetType():回傳一個型態為System.Type的變數,表示該陣列的資料型態。

(3) 其他和陣列有關的方法:

Array.Equals(陣列一,陣列二):回傳一個bool。若其值為True,表示該陣列一陣列二相等,否則其值為False

Array.Clear(陣列,N,L):將該陣列自序數N開始連續共L個元素(包含序數N所對應的元素),都設為0或是false或空字串。

Array.IndexOf(陣列,):回傳一個int。搜尋該陣列中,是否有哪個元素的值是。若有則回傳其序數,若無則回傳-1。若有兩個以上元素的值是,則回傳序數最小者的序數。

Array.Sort(陣列):將該陣列進行遞增排序。

Array.Reverse(陣列):將該陣列的順序顛倒。

 

 

 

上一篇:參考資料-鍵盤按鍵名稱與按鍵編碼的對應表

下一篇:list

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

遞迴函式:

(1) 遞迴函式的基本使用法:

遞迴函式就是在回傳變數時呼叫其本身。如下例:

public int get_q(int N_, int p_)    //這就是我們要討論的遞迴函式

{

      if (N_ % p_ != 0) { return get_q(N_ - 1, p_); }  //遞迴函式在回傳變數時呼叫其本身

      else {return N_/p_;}

}

public Form1()

{ InitializeComponent();}

private void Form1_Load(object sender, EventArgs e)

{

      int q=get_q(60,7);

      textBox1.Text = q.ToString();

}

註一:上述的遞迴函式之寫法,其實用for迴圈就可以取代,算是「大才小用」。遞迴函式真正的用途應是用在函式之執行路徑遇到「分岔點」的時候。因無法預先知曉分岔點的數量、以及分岔過後的函式路徑,故也不知道到底要使用幾個for迴圈,就必須靠遞迴函式解決。函式之執行路徑的問題牽涉到演算法的撰寫,故不在此探討。

(2) 遞迴函式的次數限制、如何解除該限制:

(2-1) C#應用程式中,函式的遞迴數目有其限制。也就是說,若函式執行超過N次,C#會懷疑該函式可能有無限遞迴的情況而自動跳出。這個N之大小,與函式所使用到的記憶體大小、其運算量、作業系統設定等等有關。如以下範例:

int N = 0;

int N_max = 12000;   //此變數N_max為遞迴函式所能執行的最大次數

public int add(int a)

{

    N++;

    if (N >= N_max){ return a; }

    else { return add(a + 1); }

}

public Form1()

{   InitializeComponent(); }

private void Form1_Load(object sender, EventArgs e)

{

    textBox1.Text = add(1).ToString();

}

經筆者以自家電腦測試,該程式可以順利執行,執行之後textBox中顯示:12000,這表示該遞迴函式add確實順利地完成了12000次的遞迴。但若是把int N_max = 12000;改成int N_max = 13000;,程式執行時便會出錯,錯誤訊息提示為:請確定沒有無限迴圈或無限遞迴的情況。依程式碼來看,程式只是要求add函式遞迴13000次,怎麼可能會出現無限遞迴呢?此乃C#為此函式所配置的記憶空間不足,無法執行13000次,導致C#誤認為出現無限遞迴。而經上述測試可知,C#add函式所配置的記憶空間所允許add函式的最大遞迴次數N,是介於1200013000之間。

(2-2) 欲讓遞迴函式突破該記憶體空間的限制、而能執行更多次遞迴,須建立一個新的執行緒、一個自訂的類別,並為該執行緒配置更多的記憶空間、以該新類別儲存函式與參數與回傳值,然後用此執行緒來執行該遞迴函式。寫法改成:

(註:要使用Thread物件(執行緒),須在程式開頭寫下:using System.Threading;

class add_function_environment  //自訂的類別,也就是「函式環境」

{

    // par set

    public int a;    //函式add所用的參數

 

    // return value

    public int result;    //函式add的回傳變數

 

    public int N = 0, N_max = 13000;    //函式add所用的全域變數

    public add_function_environment(int a_) { a = a_; }

    public void add(object obj)  //遞迴函式add,已成為函式環境中的成員函式

    {              

        N++;

        if (N >= N_max) { result = a; return; }

        else { a++;  add(obj); }

    }          

}

public Form1()

{   InitializeComponent();}

private void Form1_Load(object sender, EventArgs e)

{

    add_function_environment add_fe = new add_function_environment(1);

    Thread th_for_add = new Thread(new ParameterizedThreadStart(add_fe.add), 2000000);

    th_for_add.Start();

    th_for_add.Join();

 

    textBox1.Text = add_fe.result.ToString();

}

具體說明一一如下:

自訂的類別add_function_environment是遞迴函式add的函式環境。一個函式的環境中,包含了該函式、及所有該函式執行時所需要的全域變數、參數、回傳變數等。若函式為遞迴函式、或函式須對某變數進行作用後回傳該變數、或函式有超過一個回傳變數時,函式環境就可派上用場。而原本的遞迴函式add已成為函式環境的成員函式,要注意的是,add函式所要使用的參數不可在參數列中定義,而是定義成函式環境的成員函式,參數列必須寫為object 自訂名稱,且add函式的回傳值必須是void,這些都是為了讓自定的執行緒能夠執行該遞迴函式。

執行緒(Thread)的宣告方式之一為:

Thread 執行緒名稱 = new Thread(new ParameterizedThreadStart(函式), 堆疊大小);

其中,函式即是該執行緒所要執行的函式,其回傳變數型態必須為void,其參數列必須為object 自訂名稱,否則會出錯。而堆疊大小為一整數,表示系統分配給該執行緒的總記憶空間大小,其單位為Bytes,預設值通常為1MB(約1000000 Bytes)。堆疊大小之設定,端看程式設計者欲使遞迴函式遞迴多少次而定。

執行緒物件的使用方式:

執行緒物件.Start():開始執行該執行緒。

執行緒物件.Join():開始執行該執行緒後,讓該執行緒與執行緒一起執行,並且使在該執行緒在執行完畢之前不得執行下一道指令。

函式環境物件的使用方式:

宣告一函式環境物件,就是在宣告一函式的參數。如:

add_function_environment add_fe = new add_function_environment(1);

就是在宣告add函式的參數為1

要取回函式的回傳變數,只需從函式環境物件中呼叫即可,如:

add_fe.result 就是add函式執行後的回傳值。

 

 

 

上一篇:匿名函式

下一篇:類別的宣告

按此前往C#完整教學目錄

文章標籤

埃伯 發表在 痞客邦 留言(0) 人氣()

1 23