### PPT5 - NHU IMBI Lab

```第五部分
1
C#程式設計 – 南華大學資管系
C# 程式設計

 若第二維配置的元素個數都相同，有時會造成記

“郭靖”
C#程式設計
 3個班級的學生人數並不相同
“黃蓉”

“小龍女”

“趙敏”
“周伯通”
(1) 宣告與建立Jagged Array //動態配置
string[ ][ ] classes = new string[3][ ]; // classes.Length = ?
classes[0] = new string[2]; // classes[0].Length = ?
classes[1] = new string[3]; // classes[1].Length = ?
classes[2] = new string[2]; // classes[2].Length = ?
2

classes
0
1
●
2
C#程式設計

0
0
1
1 ●
0
1
●
2
(2) 給值
classes[0][0] = “郭靖”;
classes[0][1] = “黃蓉”;
classes[1][0] = “楊過”;
classes[1][1] = “小龍女”; classes[1][2] = “周伯通”;
classes[2][0] = “張無忌”; classes[2][1] = “趙敏”;
3

(3) 建立陣列時同時給初值
(a) string[ ][ ] classes = new string [3][ ];
C#程式設計
classes[0] = new string[ ] /*不可省略*/{“郭靖”, ”黃蓉”};
classes[1] = new string[ ] { “楊過”, ”小龍女”, ”周伯通”};
classes[2] = new string[ ] {“張無忌”, ”趙敏”};
(b) string[][] classes = new string[][] {
new string[] {“郭靖”, ”黃蓉”},
new string[] {“楊過”, ”小龍女”, ”周伯通”},
new string[] {“張無忌”, ”趙敏”}
};
4

(4) 使用巢狀迴圈走訪不規則陣列
(a) for (int i = 0; i < classes.Length; i++) {
C#程式設計
for (int j = 0; j < classes[i].Length; j++)
Console.Write(classes[i][j] + ” “);
Console.WriteLine();
}
(b) foreach (string[] c in classes) {
foreach (string s in c)
Console.Write(s + ” “);
Console.WriteLine();
}
5

(a) 表單載入時，
C#程式設計
lblCounter.Text = “共有0個顧客”;
(b) 配置紀錄交易的實體成員
// 假設至多30筆交易
string[][] trans = new string [30][];
char[] gender = new char[30];
string[] name = new string [30];
int Counter = 0;
6

(c) 輸入資料，按”輸入”鈕
if (Counter >= 30) MessageBox.Show(“儲存空間已滿”, ”錯誤”);
else { //紀錄交易的相關資訊
C#程式設計
name [ Counter ] = txtName.Text;
if (rdbMale.Checked) gender[ Counter ] = ‘男’;
else gender[ Counter ] = ‘女’;
// 檢查共買了多少商品
int ctr = 0;
if (CheckBox1.Checked) ctr++;
…
if (CheckBox5.Checked) ctr++;
// 動態配置儲存交易商品的陣列
trans[ Counter ] = new string[ ctr ];
7

// 儲存購買的商品名稱
ctr = 0;
…
if (CheckBox5.Checked) trans[ Counter ][ ctr++ ] = CheckBox5.Text;
// 顯示新交易資訊
string output = “新顧客\r\n”;
output t = name[ Counter ] + ”,” + gender[ Counter ];
for (int i = 0; i < ctr; i++)
output += “,” + trans[ Counter ][ i ];
txtOutput.Text = output;
8
C#程式設計
if (CheckBox1.Checked) trans[ Counter ][ ctr++ ] = CheckBox1.Text;

Counter++; // 顧客數加1
lblCounter.Text = “共有” + Counter + ”位顧客”;
C#程式設計
//清除介面上輸入的資料
txtName.Text = “ ”;
rdbMale.Checked = true;
CheckBox1.Checked = false;
…
CheckBox5.Checked = false;
txtName.Focus(); // 取得焦點
} // else 紀錄交易的相關資訊
9

(d) 按”列表”鈕
string str = “顧客列表\r\n”;
str += (i+1) + ”: ”;
str += name[i] + ”, ” + gender[i];
//輸出購買的所有商品
C#程式設計
for (int i = 0; i < Counter; i++) {
//建立第i位顧客的交易資訊
for(int j = 0; j < trans[i].Length; j++)
str += “, ” + trans[i][j];
str += “\r\n”;
}
txtOutput.Text = str;
txtName.Focus();
10

(e) 按”搜尋”鈕
C#程式設計
string n = txtName.Text;
int i = 0;
for (i = 0; i < Counter; i++)
if( name[ i ] == n) break;
if( i < Counter ) { //找到
string str = “!!! 搜尋結果 !!!\r\n”;
str += name[ i ] + ”, ” + gender[ i ];
for (int j = 0; j < trans[i].Length; j++) str += “, ” + trans[ i ][ j ];
txtOutput.Text = str;
} else
txtOutput.Text = “!!! 搜尋結果 !!!\r\n沒有找到” + n;
txtName.Text = “”;
txtName.Focus( );
11

 完成特定功能的程式片段，會在不同的地方重覆

C#程式設計

(b) 輸入5個成績，計算幾人及格，各等級

 造成程式碼冗長，而且不易維護
 將完成特定功能的程式片段組織成函式(方法)。寫

12

‧表單載入
‧按”產生數字”鈕
Button1_Click() {
// 隨機產生新數字 ，更新界面
//隨機產生新數字，更新界面
…
}
}
Button1_Click() {
gen_Rnd_Num() ;
}
C#程式設計
…
gen_Rnd_Num() ;
}
void gen_Rnd_Num() {
…
}
13

.
.
.

.
.
.

－方法的呼叫包含三個機制：
(a) 參數傳遞
(b) 控制權移轉
(c) 回傳值
C#程式設計

.
.
.

.
.
.

Interface
(使用界面)
14

void DataProcessing()
{
// 宣告變

…
getData(~);
analyzeData(~);
outputData(~);
}

void getData(~){
…
}
void
analyzeData(~){
analysis1(~);
analysis2(~);
}
void
outputData(~){
…
void
analysis1(~){
…
}
void
analysis2(~){
…
C#程式設計

DataProcessing() {
// 宣告變數
…
// 取得資料
…
// 分析一
…
// 分析二
…
// 輸出結果
…
}
15

 C#函數是一個可以重覆執行的程式區塊。在C#

C#程式設計
 事件處理程序、類別或物件的成員方法。
 自訂功能的函數：將程式區塊使用一個函數名

16

[存取修飾詞] 傳回值型態 方法名稱(參數1，參數2….)
{
C#程式設計

return 值|運算式;
}
bool isPass (int s) {
if (s >= 60) return true;
else return false;
}
void showTitle() {
lblOutput.Text = “C#程式設計\n”;
}
if (s >= 90) return ‘A’;
else if(s >= 80) return ‘B’;
else if(s >= 70) return ‘C’;
else if(s >= 60) return ‘D’;
else return ‘E’;
}
17

(1) string res = “”;
if( S1 >= 60 ) res += S1 + ”:及格, ”;
else res += S1 + ”:不及格, ”;
C#程式設計
int S1 = Convert.ToInt32( txtNum1.Text );
if( S1 >= 90 ) res += “等級為A\r\n”;
else if ( S1 >= 80 ) res += “等級為B\r\n”;
…
else res += “等級為E\r\n”;
… //S2, S3, S4, S5相同作法
18

(2) 使用函數呼叫
int S1 = Convert.ToInt32( txtNum1.Text );
C#程式設計
string res = “”;
if( isPass( S1 ) ) res += S1+”:及格, ”;
else res += S1+”:不及格, ”;
res += “等級為” + ScoreToGrade( S1 ) + ”\r\n”;
…
//S2, S3, S4, S5相同作法
19

int[] s = new int[5];
s[0] = Convert.ToInt32( txtNum1.Text );
…
string res = “”;
C#程式設計
s[4] = Convert.ToInt32( txtNum5.Text );
for (int i = 0; i < 5; i++) {
if ( ispass( s[ i ] ) ) res += s[ i ] + ”:及格, ”;
else res += s[ i ] + ”:不及格, ”;
res += “等級為” + ScoreToGrade( s[ i ] ) + ”\r\n”;
}
txtOutput.Text = res;
20

(a) int pass = 0;
int A = 0, B = 0, C = 0, D = 0, E = 0; //使用五個變數來記錄
for( int i = 0; i < 5; i++) {
else res += s[ i ] + ”不及格, ”;
char g = ScoreToGrade( s[ i ] );
C#程式設計
if( ispass( s[ i ] ) ) { res += s[ i ] + ”:及格, ”; pass++; }
res += “等級為”+ g + ”\r\n”;
switch( g ) {
case ‘A’: A++; break;
case ‘B’: B++; break;
…
case ‘E’: E++; break;
}
}
21

(一) 2/2
// 輸出統計資訊
res += “等級A” + A + ”人\r\n”;
C#程式設計
res += “及格:” + pass + ”人\r\n”;
…
res += “等級E” + E + ”人\r\n”;
txtOutput.Text = res;
22

(b) int pass = 0;
int[] ctr = {0, 0, 0, 0, 0}; //使用陣列來記錄
0
1
2
3
4
0
0
0
0
0
‘A’-’A’
‘B’-’A’
C#程式設計
ctr
‘C’-’A’ ‘D’-’A’ ‘E’-’A’
23

for (int i = 0; i < 5; i++) {
if ( ispass( s[ i ] ) ){ res += s[ i ] + ”:及格, ”;
pass++; }
else res += s[ i ] + ”:不及格, ”;
res += “等級為” + g + ”\r\n”;
ctr[ g - ’A’ ]++;
C#程式設計
char g = ScoreToGrade( s [ i ] );
}
//輸出統計資訊
res += “及格：” + pass + ”人\r\n”;
for (int i = 0; i < 5; i++)
res += “等級”+ (char)(‘A’ + i) + ”:” + ctr[ i ] + ”人\r\n”;
txtOutput.Text = res;
24

 將變數值(複製一份)傳入函數，在函數內無法變更此變數的值
 C#預設使用傳值呼叫(Call by value)
 傳遞陣列(傳值，此值是陣列的reference)
int sum = 0;
for (int i = 0; i < a.Length; i++)
sum += a[ i ];
return sum;
C#程式設計
int SumArray( int[] a ) {
}
 練習：輸出五個成績的和與平均
int sum = SumArray( s );
res += “和 = ” + sum + ”\r\n”;
res += “平均 = ” + (sum / 5.0) + ”\r\n”;
25

 將變數的位址傳入函數，在函數內可透過該位址”存” 、”取”

 交換兩變數的值
(b) call by ref (√)
void swap(ref int a, ref int b) {
int t = a;
a = b;
b = t;
}
……
int a = 10, b = 5;
swap(ref a, ref b);
……
C#程式設計
(a) call by value (X)
void swap(int a, int b){
int t = a;
a = b;
b = t;
}
……
int a = 10, b = 5;
swap(a, b);
……
26

 用來接收函數傳出來的值。其傳入的變數不需要指定初值
 計算陣列的最大和最小值
C#程式設計
void MaxMinArray(int [] a, out int max, out int min) {
max = a[0]; min = a[0];
for (int i = 1; i < a.Length; i++) {
if( a[ i ] > max ) max = a[ i ];
if( a[ i ] < min ) min = a[ i ];
}
}
 輸出5個成績的最高分和最低分
int max, min;
MaxMinArray(s, out max, out min);
res += “最高分 = ” + max + ”\r\n”;
res += “最低分 = ” + min + ”\r\n”;
27

C#的類別允許擁有兩個以上的同名方法，只需傳遞

C#程式設計

 int[] intArray = {1, 2, 3, 4, 5};
int sum = sumArray( intArray ); //OK
label1.Text = sum.ToString();
28

 double[] dArray = {10.0, 20.0, 30.0, 40.0, 50.0};
 定義能處理double Array和的方法
double sumArray( double[] a ) {
double sum = 0.0;
for (int i = 0; i < a.Length; i++)
sum += a[ i ];
return sum;
}
→ OK, 依參數型態的不同，呼叫對應的方法
C#程式設計
double dSum = sumArray( dArray );
→ Error: 無法從double[] 轉換為int[]
29

 匯入System.IO名稱空間，就可以使用相關的I/O類別來存

(Streams)。
C#程式設計
 利用OpenFileDialog控制項和SaveFileDialog控制項來選擇
「開啟」和「儲存」的檔案。(p.13-38)

30

成績資料的輸入
名字用一維陣列來儲存
C#程式設計
成績用二維陣列來儲存
 配置儲存資料的記憶體
const int MAX_CAPACITY = 30; (p. 3-12)
string[] name = new string[ MAX_CAPACITY ];
int [,] scores = new int[ 2, MAX_CAPACITY ];
int counter = 0;
31

(1) 測試陣列的容量，有空間則儲存，否則提示訊息
if ( counter < MAX_CAPACITY ) {
name[ counter ] = txtName.Text;
scores[ 0, counter ] = Convert.ToInt32( txtChinese.Text );
counter++;
C#程式設計
scores[ 1, counter ] = Convert.ToInt32( txtMath.Text );
ShowData(); //在界面上顯示資料
}
else MessageBox.Show(“容量已滿”, ”錯誤”, …, …);
(2) 在界面上顯示資料( ShowData()函式 )
lblCounter.Text = “共有” + counter + ”人”;
string res = “名字\t國文\t數學\r\n”;
for( int i = 0; i < counter; i++)
res += (name[ i ] + ”\t” + scores[ 0, i ] + ”\t” + Scores[ 1, i ] + ”\r\n”);
txtOutput.Text = res;
32

(a) 新增”儲存資料”鈕
(b) 按下”儲存資料”鈕


‧name設為sfdSave
C#程式設計
‧將Filter屬性設為”資料檔案(*.txt) | *.txt | 所有檔案(*.*) | *.*”
‧RestoreDirectory設為true
‧利用FileName屬性取得選取的檔案完整路徑
‧若在Dialog中選擇的檔案已存在，則會顯示”該檔案已存在，

‧若輸入test，則FileName為……\test.txt，但尚未產生該檔案。
33

 加入Using System.IO;

(p.13-14, P.13-21)
if ( sfdSave.ShowDialog() == DialogResult.OK ) {
FileInfo finfo = new FileInfo( sfdSave.FileName );
StreamWriter sw = finfo.CreateText();
for( int i = 0; i < counter; i++ ) {
sw.WritLine( name[ i ] );
sw.WritLine( scores[ 0, i ] );
sw.WritLine( scores[ 1, i ] );
}
sw.Flush();
sw.Close();
}
C#程式設計
 利用多載的WriterLine(~)方法儲存資料 (p.13-22) (檔案資料的儲存格式)
 關閉檔案串流 (p.13-23)
 程式碼
34

 利用OpenFileDialog控制項來選擇檔案，設定Filter,
RestoreDirectory屬性 (p.13-40)
C#程式設計
 利用FileInfo物件的OpenText()開啟檔案，並得到
 回傳值是string 物件
 利用Convert.ToInt32(~)轉換成int
 利用Peek()方法，判斷是否end of file (-1)
 關閉串流
 更新界面的輸出 ( 利用ShowData() )
35

 程式碼
C#程式設計
if( ofdOpen.ShowDialog() == DialogResult.OK ) {
FileInfo finfo = new FileInfo( ofdOpen.FileName );
int i = 0;
while ( sr.Peek() >= 0 ) {
scores[ 0, i ] = Convert.ToInt32( sr.ReadLine() );
scores[ 1, i ] = Convert.ToInt32( sr.ReadLine() );
i++;
}
sr.Close();
counter = i;
ShowData();
}
36

Binary
PeekChar()
Close()

Write(Type)
File
Flush()
Stream
Close()
Binary
Writer
C#程式設計
File
Stream

 使用Filestream串流物件(二進位串流)來開啟底層的二進位檔案。開啟

 使用BinaryWriter物件將基本型態的資料寫入二進位串流 (p.13-34)
 在FileDialog控制項的Filter屬性中增加”二元檔案(*.dat) | *.dat”
37

if ( sfdSave.ShowDialog() == DialogResult.OK ) {
FileStream fs = new FileStream( sfdSave.FileName, FileMode.Create);
BinaryWriter bw = new BinaryWriter( fs );
for ( int i = 0; i < counter; i++ ) {
bw.Write( name[ i ] );
C#程式設計
// 寫出資料
bw.Write( scores[ 0, i ] );
bw.Write( scores[ 1, i ] );
}
//關閉檔案
bw.Flush();
bw.Close();
fs.Close();
}
38

if ( ofdOpen.ShowDialog() == DialogResult.OK ) {
FileStream fs = new File Stream( ofdOpen.FileName, FileMode.Open );
int i = 0;
C#程式設計
while( br.PeekChar() >= 0 ) {
scores[ 0, i ] = br.ReadInt32();
scores[ 1, i ] = br.ReadInt32();
i++;
}
br.Close();
fs.Close();
counter = i;
ShowData();
}
39
```