--- title: C# tags: C#筆記 --- # C# 内容 以下内容環境都為 * .Net 5.0 * C# 9.0 * Visual Studio Professional 2019 16.8.3 * Windows 10專業版 * 開發環境->Console Application > 以下所有範例//號為輸出結果 ## 基礎概念 ### 快捷鍵 | 功能 | 快捷鍵 | | -------------- | -------- | | 全部注解 | Ctrl+K+C | | 取消注解 | Ctrl+K+U | | 格式化整份文件 | Ctrl+K+D | | 格式化選區範圍 | Ctrl+K+F | | 移動至定義 |F12 | | 設定中斷點 | F9 | ### Hello World 基礎的語法如下 ```csharp= using System;//這是一個命名空間的聲明,告訴編譯器我們將使用System命名空間中的類和函數。 namespace Exercise//這是一個命名空間的定義,用於將程式中的類和其他成員進行組織和分類。在這個例子中,我們將所有的程式碼放在Exercise命名空間中。 { class Program//這是一個類的定義。在這個例子中,我們定義了一個名為Program的類。 { static void Main(string[] args)//這是一個方法的定義,名為Main。它是程序的進入點,也是程序開始執行的地方。static 關鍵字表示該方法是靜態方法,可以直接從類中調用,而不需要實例化類。void 表示該方法不返回任何值。string[] args 是一個參數,用於接收命令行參數。 { Console.WriteLine("Hello World!");//這是一個方法調用,使用Console類中的WriteLine方法。該方法的作用是在控制台上輸出一行文本。在這個例子中,它將輸出字串"Hello World!"。 Console.Beep();//用於在控制台應用程式中產生一個聲音信號。 /* 這是一個多行註解 可以跨越多行 */ } } } // Hello World ``` ### 逸出序列(Escape sequence) 是一種在字串中插入特殊字符的表示方式。當你想要在字串中表示無法直接輸入的特殊字符時,你可以使用逸出序列。在C#和許多其他程式語言中,逸出序列以反斜線(\)開頭,後面跟著一個或多個字符。 下面是一些常見的C#逸出序列: | 符號 | 用途 | | ------ | ------------------- | | '\\' | 單引號 | | '\\"' | 雙引號 | | '\\\\' | 反斜線 | | '\\n' | 換行 | | '\\t' | 水平定位字元(Tab) | | '\\b' | 退格 | | '\\f' | 換頁 | | '\\r' | 回車 | | '\\uxxxx' | Unicode字元,其中xxxx是該字元的16進位碼點值(例如\u0041表示大寫字母'A') | 以下例子是以\n作爲範例 ```csharp= using System; namespace Exercise2 { class Program { static void Main(string[] args) { String Message = "Hello \nWorld"; Console.WriteLine(Message); } } } /* Hello World /* ``` ### Variable(變數) 一般在實作變數的時候都會以2個步驟爲主 **Step1**:Declaration(宣告) **Step2**:Initialization(初始化) >在宣告的時候有一個類型比較特殊它就是->**var** >這個類型比較特別,它並不需要賦予任何類型,在宣告完后必須要初始化一個值。它會自己去判定值的類型。 #### 常見的宣告類型 | 類型 | 範例 | 説明 | | ------ | --------------- | ------ | | Int | 1,2,3,4 | 整數 | | char | 'A','B','C' | 字符 | | String | chong,lit,wei | 字串 | | Double | 2.48,2,47,2,479 | 小數點 | | Float | 2.48,2,47,2,479 | 小數點 | | Bool | True,False | 布林值 | #### Float與Double的差別 | 主要差異 | Double | Float | | -------- | ------ | ----- | | 精度|雙精度浮點數,提供更高的精度。它占用 8 個字節(64 位元),可以表示更大範圍和更高精度的數值。它的有效位數約為 15-17 位。|單精度浮點數,提供較低的精度。它占用4個字節(32 位元),可以表示較小範圍和較低精度的數值。它的有效位數約為 6-9 位。 | | 取值範圍 | 取值範圍比 float 更大。它可以表示的數字範圍從很小的負數到很大的正數,包括科學計數法表示的數字。 | 取值範圍比 double 小,它可以表示的數字範圍較窄,但仍然足夠應對大多數一般情況。 | | 精度損失 | 使用較少的位元組,它的精度較低,因此在進行數學計算或存儲需要高精度的數值時,可能會發生精度損失的情況。 | 提供了更高的精度,因此在需要更高精度的計算場景下,它更為常用。 | ```csharp= using System; namespace Exercise3_Variable { class Program { static void Main(string[] args) { int x; //declaration x = 123;//initialization int y = 321; //declaration + initialization Console.WriteLine(x); Console.WriteLine(y); int z = x + y; Console.WriteLine(z); int age = 26;// while integer Console.WriteLine("You age is " + age);//輸出字串+變數 double height = 179.8;//decimal number Console.WriteLine("Your height is " + height); bool alive = true;//true of false Console.WriteLine("Are you alive? " + alive); char symbol = '@'; Console.WriteLine("Your symbol is: " + symbol); string name = "Chong"; Console.WriteLine("Hello " + name); } } } /* 123 321 444 You age is 26 Your height is 179.8 Are you alive? True Your symbol is: @ Hello Chong */ ``` >若宣告的變數與c#的關鍵字是重複的話可以在變數名稱前面放@,那該變數名稱儘管與關鍵字是一樣的它也會被當成是一個變數。 >例如int @class=10; 這樣使用 @class 作為變數名稱而不是作爲類別的方式宣告 ### Constant(常數) 常數(constants)是一種具有固定值的變數,其值在聲明之後不能更改。常數用於存儲在程式執行期間不會更改的數值或資訊。在C#中,常數聲明使用 const 關鍵字。 ```csharp= using System; namespace Exercise4_Constants { class Program { static void Main(string[] args) { const double pi = 3.14159;//把pi的數值固定并且不能修改 //pi=3.123如果重新賦予值的話系統會報錯 Console.WriteLine(pi); } } } //3.14159 ``` ### Void的使用時機 在C#中,void是一種表示方法或函數不返回任何值的返回類型。如果是需要回傳值的話則不需要放void。 void範例(無需回傳任何值) ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Void { class Program { static void Main(string[] args) { string user = Console.ReadLine(); if (user != null) { SelectOption(user); } void SelectOption(string selection)//void是不需要Return Value { Console.WriteLine("selection is " + selection); } } } } //c(輸入) //selection is c(輸出) ``` 需要回傳值範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Void { class Program { static void Main(string[] args) { int c, d; c = Convert.ToInt32(Console.ReadLine()); d = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("The ans is = " + Add(c, d)); int Add(int a,int b)//若需要回傳結果的話,則必須要在函數名稱前面寫入相對應的類型 { return a + b;//結果回傳 } } } } //2 //3 //The ans is = 5 ``` ### Type Casting(類型轉換) 是將一個數據類型轉換為另一個數據類型的過程。在C#中,類型轉換有兩種形式:隱式轉換(Implicit casting)和显式轉換(Explicit casting)。 * 隱式轉換(Implicit casting):隱式轉換是指在不造成數據損失的情況下,將一個小範圍數據類型轉換為大範圍數據類型的轉換。在這種情況下,編譯器會自動進行類型轉換,不需要額外的代碼。例如,將一個 int 數字賦值給一個 double 變數: ```csharp= int number = 10; double result = number; ``` 在這個例子中,int 型的 number 變數被隱式轉換為 double 型的 result 變數。 * 显式轉換(Explicit casting):显式轉換是指將一個大範圍數據類型轉換為小範圍數據類型的轉換,或在可能造成數據損失的情況下進行特定的轉換。在這種情況下,需要使用顯式轉換運算符(cast operator)來明確指定類型轉換。例如,將一個 double 數字轉換為 int 整數: ```csharp= double number = 3.14; int result = (int)number; ``` 在這個例子中,double 型的 number 變數被顯式轉換為 int 型的 result 變數,使用 (int) 來表示顯式轉換。 在進行類型轉換時需要注意以下幾點 * 在進行類型轉換時,需要確保目標類型可以容納源類型的值,否則可能會發生數據截斷或溢出的情況。 * 有些類型之間的轉換是不允許的,或者需要顯式轉換操作符進行明確指定。 * 在使用顯式轉換時,如果轉換無效或不安全,可能會引發編譯時錯誤或運行時異常。 ```csharp= using System; namespace Exercise5_Type_Casting { class Program { static void Main(string[] args) { double a = 3.14; int b = Convert.ToInt32(a);//透過convert的方式把原本double a的值轉型成Int類型 int c = 123; double d = Convert.ToDouble(c)+0.1; int e = 321; string f = Convert.ToString(e); string g = "$"; char h = Convert.ToChar(g); string i = "true"; bool j = Convert.ToBoolean(i); Console.WriteLine(b); Console.WriteLine(b.GetType());//可以透過GetType的方式來顯示當前值是屬於什麽類別 Console.WriteLine(d); Console.WriteLine(d.GetType()); Console.WriteLine(f); Console.WriteLine(f.GetType()); Console.WriteLine(h); Console.WriteLine(h.GetType()); Console.WriteLine(i); Console.WriteLine(j.GetType()); } } } /* 3 System.Int32 123.1 System.Double 321 System.String $ System.Char true System.Boolean /* ``` ### User Input(使用者輸入) ```csharp= using System; namespace Exercise6_User_Input { class Program { static void Main(string[] args) { Console.WriteLine("What's Your Name:"); string name = Console.ReadLine();//把使用者的輸入值存到name變數裏面 Console.WriteLine("What's Your Age:"); int age = Convert.ToInt32(Console.ReadLine());//如果是要把輸入的數字轉成int的話必須先轉換形態 Console.WriteLine("Hello " + name); Console.WriteLine("Your Age is " + age + " years old"); } } } /* What's Your Name: chong#輸入 What's Your Age: 26#輸入 Hello chong Your Age is 26 years old */ ``` ### Arithmetic Operators(算術運算符) ```csharp= using System; namespace Exercise7_arithmetic_operators { class Program { static void Main(string[] args) { int friend = 5;//宣告一個變數 /* friend = friend + 1;//自增的寫法(第一種) friend += 2;//自增的第二種寫法 friend++;//自增的第三種寫法,每次會+1 friend = friend - 1;//自減的寫法(第一種) friend -= 2;//自減的第二種寫法 friend--;//自減的第三種寫法,每次會-1 friend =friend *2 //乘法 friend *= 2//第二種寫法 friend = friend / 2;//除法的話則是會取整數不會顯示餘數 以這裏的例子的話就是5/2 會顯示的是2 friend /= 2除法的第二種寫法 friend = friend % 2;//%的話則是取餘數,以這裏的例子的話就是5/2 會顯示的是1 friend = friend ** 2;//用於計算一個數的指數以這裏的例子的話就是5 的2次方 */ } } } ``` ### Math Class(數學類別) 是C#中的一個數學類,位於 System 命名空間中。它提供了許多數學相關的靜態方法和常量,用於執行各種數學運算和計算。以下表格是Math類別中常用的功能分類 **數學函數** | 功能名稱 | 返回值 | | ---------- | ------ | | Math.Sqrt()| 返回一個數的平方根 | | Math.Pow() | 返回一個數的指定次方 | | Math.Round() | 對一個數執行四捨五入 | | Math.Abs() | 返回一個數的絕對值 | **三角函數** | 功能名稱 | 返回值 | | -------- | -------- | | Math.Sin() | 返回一個角度的正弦值 | | Math.Cos() | 返回一個角度的餘弦值 | | Math.Tan() | 返回一個角度的正切值 | | Math.Asin() | 返回一個數的反正弦值 | | Math.Acos() | 返回一個數的反餘弦值 | | Math.Atan() | 返回一個數的反正切值 | **對數函數** | 功能名稱 | 返回值 | | ---------- | -------- | | Math.Log10() | 返回一個數的以10為底的對數 | | Math.Log() | 返回一個數的自然對數 | **最大值和最小值** | 功能名稱 | 返回值 | | ---------- | -------- | | Math.Max() | 返回兩個數中的最大值 | | Math.Min() | 返回兩個數中的最小值 | **常數** | 功能名稱 | 返回值 | | -------- | -------- | | Math.PI | 圓周率(π)的近似值 | | Math.E | 自然對數的底數(e)的近似值 | ```csharp= using System; namespace Exercise8_Math_Class { class Program { static void Main(string[] args) { double x = 3; double y = 4; //double a = Math.Pow(x, 2); //計算x的2次方 //double b = Math.Sqrt(x);//計算x的開根號 //double c = Math.Abs(x);//計算x的絕對值 //double d = Math.Round(x);//計算x的近似值四捨五入 //double e = Math.Ceiling(x);//計算x的向上取整數如果x在3.0的話則是會取3 如果是在3.01~3.99的話則是會取4 //double f = Math.Floor(x);//計算x的向下取整,返回小於或等於該數值的最大整數 double g = Math.Max(x, y);//計算兩個數字之間的最大值 最小值的話Max改成Min即可 Console.WriteLine(g); } } } //4 ``` ### Random Number(隨機數字) 在C#中生成隨機數,你可以使用 Random 類。Random 類提供了多種方法和屬性,用於生成隨機數。 ```csharp= using System; namespace Exercise9_Random_Number { class Program { static void Main(string[] args) { Random random = new Random();//創建一個 Random 對象並將其賦值給名為 random 的變數,使用 new 關鍵字創建一個 Random 對象的實例。這意味著我們正在創建一個可以使用的 Random 對象。 int num= random.Next(1,6);//生成一個1~5之間的數字 double num2 = random.NextDouble();//生成一個介於0.0~1.0之間的隨機浮點數 bool randomBool = random.Next(2) == 0;//這行程式碼將比較結果賦值給名為 randomBool 的布林變數。如果生成的隨機整數等於 0,則 randomBool 的值為 true;如果生成的隨機整數不等於 0,則 randomBool 的值為 false。 Console.WriteLine(randomBool); } } } //False或者True ``` ### Hypotenuse_Calculator_Program(計算直角三角形斜邊) ```csharp= using System; namespace Exercise10_hypotenuse_calculator_program { class Program { static void Main(string[] args) { /* 計算直角三角形斜邊的公式是c=a^2+b^2的開根號 */ Console.WriteLine("Enter side A"); double a = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("Enter side B"); double b= Convert.ToDouble(Console.ReadLine()); double c = Math.Sqrt((a * a) + (b * b));//先計算完a和b的平方加在一起后進行開根號 Console.WriteLine("The hypotenuse is: " + c); } } } /* Enter side A 3 輸入 Enter side B 4 輸入 The hypotenuse is: 5 */ ``` ### String Method(字串處理方法) ```csharp= using System; namespace Exercise11_String_Method { class Program { static void Main(string[] args) { string fullname = "Chong Lit Wei"; string PhoneNumber = "0901-070205"; //fullname= fullname.ToUpper();//全大寫 //fullname = fullname.ToLower();//全小寫 //Console.WriteLine(fullname); //PhoneNumber=PhoneNumber.Replace("-", "/");//取代,兩個參數為字元char爲主,前面為要取代的字元,後面為取代后的字元 //Console.WriteLine(PhoneNumber); //string username = fullname.Insert(0,"!");//加入一個新的字串,第一個值為需要加在哪一個位置 這裏的0指的是第一個位置 而後面的參數是要加入什麽字串 //Console.WriteLine(username); //Console.WriteLine(fullname.Length);//顯示長度,包括空格 string firstname = fullname.Substring(0,5);//用於從字符串中提取子字符串的方法 有兩種寫法 一種是直接寫從什麽位置開始提取字元。另一種是寫提取位置和需要提取出多少個字元如此範例 string middlename = fullname.Substring(6,3);//代表的意思是從第六個位置開始提取后3個字元 string last_name = fullname.Substring(10);//代表的意思是從第十個位置開始提取一直到結束 Console.WriteLine(firstname); Console.WriteLine(middlename); Console.WriteLine(last_name); } } } /* Chong Lit Wei */ ``` ### If Statement(假如判別式) ```csharp= using System; namespace Exercise12_If_Statement { class Program { static void Main(string[] args) { /*範例1 用數字來做基本的if else判斷 Console.WriteLine("Please enter your age:"); int age = Convert.ToInt32(Console.ReadLine());//把輸入的數字轉換成int后存入age裏 if (age >=18) { Console.WriteLine("You are now signed up"); } else if (age < 0) { Console.WriteLine("You haven't been born yet!"); } else { Console.WriteLine("You must be 18+ to sign up!"); } */ //範例2 用字串來做基本的判斷式 Console.WriteLine("Please Enter Your Name"); string name = Console.ReadLine(); if(name== "") { Console.WriteLine("You did not enter your name!"); } else { Console.WriteLine("Hello " + name); } } } } /* Please Enter Your Name chong 輸入 Hello chong */ ``` ### Switches Switch 是一種流程控制結構,用於根據不同的值或表達式的結果來執行不同的程式碼塊。它通常用於多分支的情況,其中有多個可能的情況需要進行處理。 ```csharp= using System; namespace Exercise13_Switches { class Program { static void Main(string[] args) { Console.WriteLine("What day is today?"); string day = Console.ReadLine(); switch (day)//以day的值為基準 { case "Monday": Console.WriteLine("Is's Monday!"); break; case "Tuesday"://如果day的值是Monday的話 Console.WriteLine("Is's Tuesday!"); break; case "Wednesday": Console.WriteLine("Is's Wednesday!"); break; case "Thursday": Console.WriteLine("Is's Thursday!"); break; case "Friday": Console.WriteLine("Is's Friday!"); break; case "Saturday": Console.WriteLine("Is's Saturday!"); break; case "Sunday": Console.WriteLine("Is's Sunday!"); break; default://如果不在例外case裏面的範圍的話則會以default的功能爲主 Console.WriteLine(day + " is not a day!"); break; } } } } /* What day is today? Monday 輸入 Is's Monday! */ ``` ### Logical Operators(邏輯運算符號) 邏輯運算符用於結合和操作布林值(true/false)。C#提供了三個常用的邏輯運算符:&&(AND)、||(OR)和 !(NOT)。 ```csharp= using System; namespace Exercise14_Logical_Operators { class Program { static void Main(string[] args) { Console.WriteLine("What's the temperature outside: (C)"); double temp = Convert.ToDouble(Console.ReadLine()); if (temp >= 10 && temp <= 25)//&&(AND)的話要滿足兩個條件 { Console.WriteLine("It's warm outside!"); } else if(temp<=-50 || temp>=50)//||(OR)的話要滿足其中一個條件 { Console.WriteLine("DO NOT GO OUTSIDE!"); } //not的範例 bool a = true; bool result = !a;// Not會把操作數的布林值反轉 Console.WriteLine(result); } } } /* What's the temperature outside: (C) 25 輸入 It's warm outside! False */ ``` ### While Loops while 循環用於在滿足特定條件時重複執行程式碼塊,直到條件不再滿足為止。 在 while 循環中,只需要指定循環條件,程式碼塊會在每次迭代之前檢查條件的真假,如果條件為真,則執行程式碼塊。 ```csharp= using System; namespace Exercise15_While_Loops { class Program { static void Main(string[] args) { Console.Write("Enter your name !"); string name = Console.ReadLine(); while (name == "")//會一直執行到while loops裏面的條件結束爲止 { Console.Write("Enter your name !"); name = Console.ReadLine(); } Console.WriteLine("Hello " + name); } } } /* Enter your name!:chong chong為輸入 Hello chong */ ``` ### do-While Loops do-while循環是一種「先執行,後測試」的循環結構。這意味著無論條件是否滿足,至少會執行循環主體一次。 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { class Program { static void Main(string[] args) { int i = 0; do { Console.WriteLine(i); i++; } while (i <= 5); } } } /* 0 1 2 3 4 5 */ ``` ### For Loops for 循環用於在指定的迭代次數內重複執行程式碼塊。 在 for 循環中,需要指定初始值、循環條件和迭代遞增/遞減操作。 ```csharp= using System; namespace Exercise16_For_Loops { class Program { static void Main(string[] args) { /* for (int i=1; i<=10;i+=3)//for循環裏面裏面所需要的三個參數分別為(賦值一個初始值;條件;迭代用於在每次迭代結束後更新迭代變數的值。) { Console.WriteLine(i); } */ for (int i = 10; i >= 0; i--)//此循環的意思是 設定int i的初始值為10,如果i>0的話 每做完一次循環則會自減1次 { Console.WriteLine(i); } Console.WriteLine("End"); } } } /* 10 9 8 7 6 5 4 3 2 1 0 End */ ``` ### Nested_Loop(巢狀循環) 是一種在循環內部包含另一個循環的結構。它在C#中常用於處理多維數組、矩陣、二維表格等需要雙重迭代的情況。巢狀循環允許在外部循環的每次迭代中,內部循環完整地遍歷一次。 ```csharp= using System; namespace Exercise17_Nested_Loop { class Program { static void Main(string[] args) { Console.Write("How Many Rows:"); int rows = Convert.ToInt32(Console.ReadLine()); Console.Write("How Many Columns:"); int columns = Convert.ToInt32(Console.ReadLine()); Console.Write("What Symbol:"); char symbols = Convert.ToChar(Console.ReadLine()); for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++)//首先會執行 int j 的循環,內部循環遍歷完一行的符號後,才會進入下一次 int i 的循環,繼續打印下一行的符號。 { Console.Write(symbols); } Console.WriteLine(); } } } } /* How Many Rows:3 3為輸入 How Many Columns:5 5為輸入 What Symbol:* *為輸入 ***** ***** ***** */ ``` ### public static 和void的差別 | 關鍵字 | 說明 | 用途 | | ------ | ---------------------------------- | ------------------------------------------------ | | public | 存取修飾符,指定方法的訪問範圍 | 允許其他程式部分訪問該方法 | | static | 修飾符,指定方法屬於類別而不是實例 | 可以直接通過類別名稱來呼叫方法,而不需要創建對象 | | void | 返回類型,表示方法不返回任何值 | 用於描述沒有返回值的方法 | * public 存取修飾符用於指定方法的訪問範圍。當方法聲明為 public 時,其他程式部分可以訪問該方法,包括其他類別或程式集。 * static 修飾符用於指定方法屬於類別而不是特定實例。靜態方法可以直接通過類別名稱呼叫,而不需要創建類別的實例。它們通常用於提供共享的實用功能或工具方法。 * void 是一種返回類型,表示方法不返回任何值。當方法聲明為 void 時,它執行特定的操作或任務,但不生成結果值。這意味著你無法從該方法中獲取結果,也無法將其賦值給其他變數。 #### public的範例 ```csharp= using System; namespace Example { public class Person { public string Name { get; set; } public int Age { get; set; } public void Introduce() { Console.WriteLine("My name is " + Name + " and I am " + Age + " years old."); } } public class Program { public static void Main(string[] args) { Person person = new Person(); person.Name = "John"; person.Age = 30; person.Introduce(); // 其他程式邏輯... } } } ``` 在這個例子中,我們定義了一個 Person 類別,它具有 Name 和 Age 兩個公共的屬性。這些屬性使用 public 存取修飾符來指定它們可以從任何程式部分訪問。 Person 類別還有一個 Introduce 方法,它是一個公共方法,用於在控制台上介紹該人物的名字和年齡。 在 Main 方法中,我們創建了一個 Person 對象,並設定其 Name 和 Age 屬性的值。然後,我們呼叫 Introduce 方法,以在控制台上輸出該人物的介紹。 這個例子展示了如何使用 public 關鍵字來定義公共的類別、屬性和方法,從而允許其他程式部分訪問這些成員。 #### void的範例 ```csharp= using System; public class Printer { public void PrintMessage(string message) { Console.WriteLine("Printing message: " + message); } } public class Program { public static void Main(string[] args) { Printer printer = new Printer(); printer.PrintMessage("Hello, World!"); // 其他程式邏輯... } } ``` 在上面的範例中,我們創建了一個 Printer 類別,該類別具有一個 PrintMessage 方法,其返回類型為 void。這表示該方法不返回任何值。 PrintMessage 方法接收一個 string 參數 message,並將該參數的值與一個固定的消息組合後輸出到控制台。 在 Main 方法中,我們創建了一個 Printer 對象 printer,並調用其 PrintMessage 方法,將參數設置為 "Hello, World!"。由於 PrintMessage 方法的返回類型為 void,所以我們不需要將其返回值存儲在變數中。 結果是將消息 "Printing message: Hello, World!" 輸出到控制台。 這個範例展示了如何在方法聲明中使用 void 來指示該方法不返回任何值。在 Main 方法中,我們可以直接調用該方法,而無需關心其返回值。 #### static的範例 ```csharp= using System; public class MathUtils { public static int Add(int a, int b) { return a + b; } public static int Multiply(int a, int b) { return a * b; } } public class Program { public static void Main(string[] args) { int sum = MathUtils.Add(5, 3); Console.WriteLine("Sum: " + sum); int product = MathUtils.Multiply(2, 4); Console.WriteLine("Product: " + product); // 其他程式邏輯... } } ``` 在上面的範例中,我們創建了一個 MathUtils 類別,並在該類別中定義了兩個 static 方法:Add 和 Multiply。 這些方法被聲明為 static,這意味著它們屬於類別本身,而不是類別的實例。因此,我們可以直接通過類別名稱來調用這些方法,而無需創建類別的實例。 在 Main 方法中,我們使用 MathUtils.Add 方法將 5 和 3 相加,並將結果存儲在 sum 變數中。然後,我們使用 MathUtils.Multiply 方法將 2 和 4 相乘,並將結果存儲在 product 變數中。 最後,我們將 sum 和 product 的值輸出到控制台。 這個範例展示了如何使用 static 關鍵字來創建靜態方法,並在程式中直接通過類別名稱來調用這些方法。 ## 簡單練習 ### Number_Guessing_Game(範例) ```csharp= using System; namespace Exercise18_Number_Guessing_Game { class Program { static void Main(string[] args) { Random random = new Random();//用來生成一個隨機數字 bool PlayAgain = true; int min = 1;//最小值 int max = 100;//最大值 int guess;//存入使用者猜的數字 int number;//隨機生成的數字存入的變數 int guesses;//猜的次數 string response;//讓使用者輸入要不要重來一局 while (PlayAgain) { //當PlayAgain==True的時候 要重置猜的數字,猜的次數以及隨機生成一組新的隨機數和把response裏已經存進去的值清空 guess = 0; guesses = 0; response = ""; number = random.Next(min,max+1); while(guess != number) { Console.WriteLine("Guess a Number between" + min +" - " +max + ":"); guess = Convert.ToInt32(Console.ReadLine());//把玩家輸入存入guess裏 Console.WriteLine("Guess: " + guess);//顯示玩家猜的數字 if (guess >number)//判別是大於還是小於 { Console.WriteLine(guess + " Too high"); } else if (guess < number) { Console.WriteLine(guess + " Too Low"); } guesses++;//每猜一次 猜的次數會增加一次 } Console.WriteLine("Number:" + number); Console.WriteLine("You Win"); Console.WriteLine("Guesses: " + guesses);//顯示猜了幾次 Console.WriteLine("Would You like to Play Again(Y/N): "); response = Console.ReadLine(); response = response.ToUpper();//如果使用者輸入小寫的話自動轉大寫 if(response == "Y") { PlayAgain = true; } else { PlayAgain = false; } } Console.WriteLine(); Console.WriteLine("Thank for Playing!"); } } } /* Guess a Number between 1 - 100: 16 輸入 Guess: 16 16 Too high Guess a Number between 1 - 100: 13 輸入 Guess: 13 13 Too high Guess a Number between 1 - 100: 11 輸入 Guess: 11 11 Too high Guess a Number between 1 - 100: 4 輸入 Guess: 4 4 Too Low Guess a Number between 1 - 100: 7 輸入 Guess: 7 7 Too high Guess a Number between 1 - 100: 6 輸入 Guess: 6 Number:6 You Win Guesses: 6 Would You like to Play Again(Y/N): N 輸入 Thank for Playing! */ ``` ### Rock-PaPer-Scissors game ```csharp= using System; namespace Exercise19_Rock_PaPer_Scissors_game { class Program { static void Main(string[] args) { Random random = new Random();//生成一個隨機的類別 bool playagain = true;//預設游戲一開始是開始 string player;//輸入使用者的字串 string computer;//輸出電腦隨機的字串 string answer;//用來做最後是否要繼續玩 while (playagain) { player = "";//重置用 computer = ""; answer = ""; while (player != "ROCK" && player !="PAPER" && player !="SCISSORS") { Console.Write("Enter Rock Paper or Scissors:"); player = Console.ReadLine(); player = player.ToUpper(); } int randomNum = random.Next(1, 4);//讓電腦隨機抽石頭剪刀布 switch (randomNum) { case 1: computer = "ROCK"; break; case 2: computer = "PAPER"; break; case 3: computer = "SCISSORS"; break; } Console.WriteLine("Player:" + player); Console.WriteLine("Computer:"+ computer); switch (player)//用switch判別條件 { case "ROCK": if(computer == "ROCK") { Console.WriteLine("It's draw!"); } else if (computer == "PAPER") { Console.WriteLine("You Loss!"); } else { Console.WriteLine("You Win!"); } break; case "PAPER": if (computer == "ROCK") { Console.WriteLine("You Win"); } else if (computer == "PAPER") { Console.WriteLine("It's draw!"); } else { Console.WriteLine("You Loss!"); } break; case "SCISSORS": if (computer == "ROCK") { Console.WriteLine("You Loss!"); } else if (computer == "PAPER") { Console.WriteLine("You Win!"); } else { Console.WriteLine("It's draw!"); } break; } Console.WriteLine("Would You like to play again(Y/N)"); answer = Console.ReadLine(); answer = answer.ToUpper(); if(answer == "Y") { playagain = true; } else { playagain = false; Console.WriteLine("Good Bye"); } } } } } ``` ### Calculator_Program ```csharp= using System; namespace Exercise20_calculator_program { class Program { static void Main(string[] args) { do//do while的功能是會一直執行整個主程式的功能 { double num1=0; double num2=0; double result=0; Console.WriteLine("-----------------"); Console.WriteLine("Calculator Program"); Console.WriteLine("-----------------"); Console.Write("Enter Num1: "); num1 = Convert.ToDouble(Console.ReadLine()); Console.Write("Enter Num2: "); num2 = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("Enter an option:"); Console.WriteLine("+ : Add"); Console.WriteLine("- : Subtract"); Console.WriteLine("* : Multiply"); Console.WriteLine("/ : Divide"); Console.Write("Enter an option:"); switch (Console.ReadLine()) { case "+": result = num1 + num2; Console.WriteLine($"Your Reuslt= {num1} + {num2} = " + result); break; case "-": result = num1 - num2; Console.WriteLine($"Your Reuslt= {num1} - {num2} = " + result); break; case "*": result = num1 * num2; Console.WriteLine($"Your Reuslt= {num1} * {num2} = " + result); break; case "/": result = num1 / num2; Console.WriteLine($"Your Reuslt= {num1} / {num2} = " + result); break; default: Console.WriteLine("That was not a valid option"); break; } Console.WriteLine("Do you want to contunue?(Y/N):"); } while (Console.ReadLine().ToUpper() == "Y");//這裏的while是如果達成裏面的條件則會返回配合上面的do重新執行 Console.WriteLine("Good Bye!"); } } } ``` ## 進階語法&Object Oriented Programming(物件導向概念) ### Array(陣列) 在 C# 中,array(陣列)是一種固定大小的、相同類型元素的集合。它是一個連續的內存塊,可以通過索引來訪問和操作其中的元素。 以下是在C#中宣告和使用陣列的基本語法: ```csharp= // 宣告並初始化陣列 type[] arrayName = new type[length]; // 設置或獲取陣列中的元素 arrayName[index] = value; var element = arrayName[index]; // 取得陣列的長度 int length = arrayName.Length; ``` * type 是陣列中元素的類型,可以是內建的資料型別(如整數、浮點數、字元等),也可以是自定義的類型。 * arrayName 是陣列的名稱,可以根據需求自行命名。 * length 是陣列的大小,表示可以容納的元素數量。 * index 是陣列元素的索引,從 0 開始計數。 ```csharp= using System; namespace Exercise21_Array { class Program { static void Main(string[] args) { //string[] cars = { "BMW","Honda","Corvette" }; //array的宣告方法就是 類型[] 變數名稱= {陣列的内容} string[] cars = new string[3];//Array可以設定成一個固定的大小 并且不賦予任何值先 cars[0] = "Tesla";//要更改的話可以透過指定索引位置的方式更改陣列内容值 cars[1] = "Honda"; cars[2] = "BMW"; Console.WriteLine(cars[0]);//要讀出陣列裏的内容必須要在變數後面新增[索引]不然的話讀不出陣列内的内容 for (int i=0;i< cars.Length; i++)//要讀取整個陣列的話 必須要透過for的方式來讀取 使用cars.Length返回陣列cars的元素數量,也就是陣列的長度。使用 cars.Length 作為終止條件可以確保迴圈遍歷整個陣列,而不會超出陣列的範圍。 { Console.WriteLine(cars[i]); } } } } ``` ### Foreach loop foreach 是 C# 中用於遍歷集合或陣列的迴圈結構。它提供了一種簡潔且方便的方式來逐個訪問集合或陣列中的元素,而無需關注索引或迭代次數。 以下是表格for,do while,while以及foreach loop的差別 | 迴圈類型 | 說明 | 適用場景 | | -------- | ---------------------------------------------- | ------------------------------------ | | for | 最通用的迴圈結構,使用索引和迭代次數來控制迴圈 | 需要指定迭代次數,並使用索引存取元素 | | while | 根據條件的真假來重複執行程式碼塊 | 根據條件進行循環,需手動更新條件 | | do-while | 先執行程式碼塊,然後檢查條件,至少執行一次 | 至少執行一次程式碼塊,然後根據條件決定是否繼續循環 | | foreach | 用於遍歷集合或陣列中的每個元素 | 無需索引和迭代次數,只需訪問元素 | ```csharp= using System; namespace Exercise22_Foreach_Loop { class Program { static void Main(string[] args) { string[] cars = { "BMW", "Honda", "Tesla" }; foreach(string car in cars)//一開始要宣告的時候需要透過(類型 變數名稱 in 已經存在的陣列變數名稱) { Console.WriteLine(car); } } } } /* BMW Honda Tesla */ ``` ### List(列表) 在 C# 中,List是一種動態陣列,它提供了彈性的大小和方便的方法來操作集合中的元素。而List和Array的差別可以參考以下表格 | 特點 | Array | List | | ---------------- | ------------------ | ------------------------------------------ | | 大小靈活性 | 固定大小 | 動態調整大小 | | 記憶體管理 | 動態分配,固定内存 | 動態分配,自動調整内存 | | 支援的方法和屬性 | 有效的内建方法 | 豐富的内建方法如增加、插入、刪除、排序等等 | | 增加刪除效能 | 插入,刪除較耗時 | 增加刪除高效,自動調整内存 | | 處理特殊需求能力 | 較難滿足特殊需求 | 較容易滿足特殊需求 | 以下是List的範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { class Program { static void Main(string[] args) { List<string> words = new List<string>();//宣告方式List<類型> 變數名稱=new List<類型>() words.Add("1");//Add是新增一個元素進去這個List裏 words.Add("2"); words.Add("3"); words.Add("4"); words.Add("5"); words.Remove("5");//Remove是移除指定的一個元素 words.RemoveAt(0);//RemoveAt是刪除指定的索引元素 Console.WriteLine("Count of Element is " + words.Count);//Count是計算裏面有多少個元素 Console.WriteLine("Index of Element 'Four' is " + words.IndexOf("4"));//IndexOf是透過指定一個元素抓取該索引值 Console.WriteLine("Contains 'Two'?: " + words.Contains("2"));//Contains是可以確定這個值是否有在該List裏,會回傳布林值 foreach(string word in words)//利用foreach的方式來輸出list裏所有的元素 { Console.WriteLine(word); } } } } /* Count of Element is 3 Index of Element 'Four' is 2 Contains 'Two'?: True 2 3 4 */ ``` ### out Keywords out 關鍵字是用於方法參數中的一種修飾符。使用 out 修飾的參數是一種輸出參數,它允許方法在返回值之外返回額外的值。out 參數常用於需要返回多個值的情況,因為方法只能返回一個值(通常是單一的返回值)。通過使用 out 修飾的參數,你可以在方法外部接收多個值,並且不需要使用 return 關鍵字。 總之,out 關鍵字用於定義一個輸出參數,允許方法在返回值之外返回額外的值。 以下是利用out Keywords實作的範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { class Program { static void Main(string[] args) { var number = new[] { 10, -8, 2, 12, -17 };// 宣告一個整數陣列 int nonPositiveCount;// 宣告用於計算非正數的數量的變數 // 呼叫 GetOnlyPositive 方法來取得只有正數的 List, // 同時將 nonPositiveCount 變數作為輸出參數返回 var onlyPositive = GetOnlyPositive(number,out nonPositiveCount); // 逐一輸出只有正數的 List 中的元素 foreach (var positivenumber in onlyPositive) { Console.WriteLine(positivenumber); } Console.WriteLine("Count of non positive: " + nonPositiveCount);// 輸出非正數的數量 Console.ReadKey();// 等待使用者按下任意按鍵 } //// GetOnlyPositive 方法,接受一個整數陣列和一個用於計算非正數數量的輸出參數 static List<int> GetOnlyPositive(int[] numbers,out int CountOfNonPositive) { CountOfNonPositive = 0;// 初始化非正數計數為 0 var result = new List<int>();// 創建一個用於存儲只有正數的 List foreach (int num in numbers)// 遍歷整數陣列中的每個數字 { if (num > 0)// 如果數字是正數 { result.Add(num);// 將數字加入只有正數的 List } else// 如果數字是非正數(包括 0) { CountOfNonPositive++;// 非正數計數加 1 } } // 返回只有正數的 List return result; } } } /* 10 2 12 Count of non positive: 2 */ ``` ### Try-Parse方法 TryParse 是 C# 中一個常用於將字符串轉換為其他數據類型的方法,它可以確定轉換是否成功,並返回轉換後的值。 以下是TryParse的範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { class Program { static void Main(string[] args) { bool isParsingSuccessful;// 用於標記解析是否成功的變數 do { Console.WriteLine("Enter a Number:");// 提示用戶輸入數字 var user_input = Console.ReadLine();// 讀取用戶輸入的內容 // 嘗試將用戶輸入的內容轉換為整數,並將轉換結果存在 number 變數中, // 同時檢查是否成功,結果存放在 isParsingSuccessful 變數中 //Try.Parse功能裏的值代表的是(輸入的變數,out 類型 輸出的變數) isParsingSuccessful = int.TryParse(user_input, out int number); if (isParsingSuccessful) // 如果解析成功,輸出解析後的數字 { Console.WriteLine("Parsing worked, number is " + number); } else { Console.WriteLine("Parsing was not successful");// 如果解析失敗,輸出解析失敗的訊息 } } while (!isParsingSuccessful);// 如果解析失敗,重複提示用戶輸入直到解析成功 } } } ``` ### Methods(方法) 是一種用於組織和重用程式碼的結構。方法包含一組執行特定任務的語句。你可以在程式中定義方法,並根據需要多次呼叫它們。 ```csharp= using System; namespace Exercise23_Methods { class Program { static void Main(string[] args) { singHappyBirthday();//呼叫外部功能 singwithname("Lit Wei",26);//呼叫功能并且賦予相對應的值 } static void singHappyBirthday()//宣告一個功能函數 { Console.WriteLine("Happy birthday to you "); Console.WriteLine("Happy birthday to you "); Console.WriteLine("Happy birthday to you "); Console.WriteLine("Happy birthday to you "); Console.WriteLine(); } static void singwithname(string name,int age)//要呼叫這個功能的話 需要賦予兩個值 一個是字串,一個是整數 { Console.WriteLine("Happy birthday to you "+name); Console.WriteLine("You are " + age + " Years Old"); } } } /* Happy birthday to you Happy birthday to you Happy birthday to you Happy birthday to you Happy birthday to you Lit Wei You are 26 Years Old */ ``` ### Return KeyWord 關鍵字在 C# 中用於從方法中返回值,並結束方法的執行。它有兩種常見的使用情況: * 返回值:當定義方法時,可以指定方法的返回類型。使用 return 關鍵字可以將計算結果或其他需要返回的值從方法中返回給調用該方法的地方。 * 提前結束方法:return 關鍵字也可以在方法的任何地方使用,用於提前結束方法的執行並返回到調用該方法的地方。這在某些情況下可能很有用,例如檢查條件並根據結果決定是否提前結束方法。 ```csharp= using System; namespace Exercise24_Return_Keyword { class Program { static void Main(string[] args) { double x; double y; double result; Console.Write("Enter in number1: "); x = Convert.ToDouble(Console.ReadLine()); Console.Write("Enter in number2: "); y = Convert.ToDouble(Console.ReadLine()); result = Multiply(x, y); Console.WriteLine("Result is : " + result); } static double Multiply(double a,double b) { double c = a * b; return c;//void 關鍵字表示方法不返回任何值。當你使用 void 作為方法的返回類型時,你不需要使用 return 關鍵字返回值。方法的執行只是完成指定的操作,而不返回任何值。如果你想讓方法返回一個值,你需要指定一個非 void 的返回類型,例如 int、string 等。當你使用 return 關鍵字時,你需要確保返回的值的類型與方法的返回類型相匹配。 } } } /*Enter in number1: 3 輸入 Enter in number2: 3 輸入 Result is : 9 */ ``` ### Method Overloading(方法重載) 是指在同一個類中定義多個具有相同名稱但參數列表不同的方法。這些方法可以擁有不同的返回類型,也可以有相同的返回類型但參數列表不同。 方法重載的目的是提供更靈活的方法調用方式,讓開發人員能夠根據不同的需求選擇適合的方法來執行相似的操作。使用方法重載可以增加代碼的可讀性和可維護性。 ```csharp= using System; namespace Exercise25_Method_Overloading { class Program { static void Main(string[] args) { double x=3; double y=4; double z=2; double result; result=Multiply(x, y, z);//透過方法重載的方式可以選擇要使用只能放兩個參數或者三個參數的功能函數、 Console.WriteLine(result); } static double Multiply(double a, double b) { double c = a * b; return c; } static double Multiply(double a, double b,double c)//方法重載可以使用同一組變數名稱,也能使用相同的方法 { double d = a * b * c; return d; } } } //24 ``` ### Params keyword params 關鍵字是 C# 中的一個特性,用於指定一個方法的可變數量參數。它允許你在方法的參數列表中指定一個類型相同的參數陣列,以便在調用該方法時能夠傳遞不同數量的參數。 ```csharp= using System; namespace Exercise26_Params_Keywords { class Program { static void Main(string[] args) { double total = checkout(1.00, 2.00, 3.00,4.00);//使用了Params 之後就可以無限量一直增加新的參數進去。 Console.Write(total); Console.WriteLine(); } static double checkout(params double [] prices)//使用Params的好處是可以在不知道使用者會輸入多少個input的情況下去運行功能宣告方式是(params 類型 [] 變數名稱) { double total=0; foreach(double price in prices)//利用foreach把每一次從total裏的價格數量放進去total裏面相加 { total = total + price; } return total; } } } // 10 ``` >params 參數必須是 方法參數列表中的最後一個參數。 每個方法只能有 一個 params 參數。 params 接收的參數其實就是一個陣列。 ### Exception Handling(異常處理) 異常處理(Exception Handling)是在程式執行過程中處理異常情況的一種機制。異常是指在程式執行期間發生的不正常狀態或錯誤,可能導致程式無法正常執行。 C# 提供了一套完整的異常處理機制,使用 try-catch-finally 區塊來捕獲和處理異常。這樣可以使程式在遇到異常時進行適當的處理,而不會導致程式的崩潰或意外終止。 下面是 try-catch-finally 區塊的基本結構: ```csharp= try { // 執行可能產生異常的程式碼 } catch (ExceptionType1 exception1) { // 處理特定類型的異常 } catch (ExceptionType2 exception2) { // 處理其他類型的異常 } finally { // 無論是否發生異常,都會執行的程式碼 } ``` 範例 ```csharp= using System; namespace Exercise27_Exception_Handling { class Program { static void Main(string[] args) { //以下是一個簡單的除法功能 double x; double y; double result; try { //透過try catch的方式來增加防呆機制 Console.Write("Enter Number1:"); x = Convert.ToDouble(Console.ReadLine()); Console.Write("Enter Number2:"); y = Convert.ToDouble(Console.ReadLine()); result = x / y; Console.WriteLine("The Result of " + x + "/" + y + " is " + result); } catch(FormatException e)//格式/類型錯誤的情況 { Console.WriteLine("Enter Only Number "); } catch(DivideByZeroException e)//被除數字=0的時候會報錯 透過try catch的方式來防呆 { Console.WriteLine("You cannot Divide by zero"); } catch(Exception e)//不知道發生什麽情況的錯誤時可以使用Exception { Console.WriteLine("Somethings Wrong"); } finally//無論是否發生異常,最後都一定會執行的程式碼 { Console.WriteLine("Thank For Visiting"); } } } } /* Enter Number1:12 //輸入 Enter Number2:abc Enter Only Number Thank For Visiting 請按任意鍵繼續 . . . */ ``` ### Conditional_Operator(條件運算符) 條件運算符(Conditional Operator),也稱為三元運算符,是 C# 中的一種運算符,用於根據條件的真假來返回不同的值。 條件運算符的語法如下: ```csharp= condition ? expression1 : expression2 ``` 這裡的 condition 是一個布爾表達式,如果條件為真,則返回 expression1 的值,否則返回 expression2 的值。 以下是一個使用條件運算符的示例: ```csharp= using System; namespace Exercise28_Conditional_operator { class Program { static void Main(string[] args) { double temperature = 20; string message; message = (temperature >= 15) ? "It's warm outside" : "it's cold outside";//Conditional_operator有點類似把if else整合起來的功能 前面的是把條件給放進去(條件)? 如果True的話做這個條件:如果False的話則做這個條件 Console.WriteLine(message); } } } //It's warm outside ``` ### String_Interpolation(字符串插值) 字符串插值(String Interpolation)是 C# 中一種方便的字串組合方式,它使得在字串中插入變數或表達式更加簡潔和易讀。 在 C# 中,可以使用 $ 符號來標記使用字符串插值的字串,並在 {} 中插入變數或表達式。插入的變數或表達式將在運行時自動計算並替換為其值。 ```csharp= using System; namespace Exercise29_String_Interpolation { class Program { static void Main(string[] args) { string first_name = "Chong "; string last_name = "Lit Wei"; int age = 26; //以下是傳統寫法 也比較複雜 Console.WriteLine("Hello " + first_name + last_name + "."); Console.WriteLine("You are " + age + " Years Old"); Console.WriteLine(); //以下是透過String_Interpolation的寫法來實作跟上面一樣的結果 Console.WriteLine($"Hello {first_name} {last_name}");//在輸出前添加$ 可以在後續輸出的結果裏透過{變數名稱}來直接顯示結果 無需透過+號來額外進行輸出 Console.WriteLine($"You are {age,-10} Years Old");//如果在變數名稱后添加數字的話則是要往後空多少格{變數名稱,需要空格多少格子}正數的話是從前面開始開始空,如果是負數的話則是結果顯示后才會空格 } } } /* Hello Chong Lit Wei. You are 26 Years Old Hello Chong Lit Wei You are 26 Years Old */ ``` 除此之外也能夠透過{}來調整小數后輸出幾位數如以下例子 ```csharp= double pi = Math.PI; string formatted = $"The value of pi is {pi:F2}"; Console.WriteLine(formatted); ``` ### Multidimensional Arrays(多維陣列) 多維陣列(Multidimensional Arrays)是 C# 中用於存儲多維數據的一種特殊類型的陣列。它是由多個維度組成的,每個維度都有自己的大小。 在 C# 中,可以使用逗號分隔的方括號 [,] 來聲明和創建多維陣列。以下是一個二維陣列的示例: ```csharp= using System; namespace Exercise30_Multidimensional_arrays { class Program { static void Main(string[] args) { string[] ford = { "Mustang", "F-150", "Explorer" }; string[] Chevy = { "Corvette", "Camero", "Silverado" }; string[] toyota = { "Corolla", "Carmy", "Rav4" }; string[,] ParkingLot = { { "Mustang", "F-150", "Explorer" }, { "Corvette", "Camero", "Silverado" }, { "Corolla", "Carmy", "Rav4" } };//[,]是 C# 中表示二維字串陣列的類型。它是一種由多行和多列組成的陣列,每個元素都是字串類型 ParkingLot[1, 1] = "Fusion";//把第一行第一列的值修改為Fusion /* foreach( string car in ParkingLot)//寫出所有陣列内的值 { Console.WriteLine(car); } */ for (int i = 0; i < ParkingLot.GetLength(0); i++) { for(int j = 0; j < ParkingLot.GetLength(1); j++)//在 C# 中,GetLength() 是一個用於陣列的方法,它可以獲取指定維度的大小。二維陣列中,GetLength(0) 返回第一維(行)的大小,GetLength(1) 返回第二維(列)的大小。 { Console.Write(ParkingLot[i, j] + " "); } Console.WriteLine(); } } } } /* Mustang F-150 Explorer Corvette Fusion Silverado Corolla Carmy Rav4 */ ``` ### Classes(類別) 在 C# 中,類(Class)是一種用於定義物件的藍圖或模板。類描述了物件的屬性(數據成員)和行為(方法成員),它是面向物件編程(OOP)的基本概念之一。 類可以包含各種成員,例如字段(變數)、屬性、方法、構造函式、事件等,用於描述物件的特徵和操作。 ```csharp= //主程式 using System; namespace Exercise31_Classes { class Program { static void Main(string[] args) { Message.hello(); Message.bye(); Message.waiting(); } } } /* Welcome to the Program Good bye i am waiting for something */ ``` ```csharp= //Message 類別程式 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Exercise31_Classes { static class Message { public static void hello()//宣告一個功能 要添加public static 才能讓主程式去呼叫這個類別裏面的功能函式 { Console.WriteLine("Welcome to the Program"); } public static void waiting()//宣告一個功能 { Console.WriteLine("i am waiting for something"); } public static void bye()//宣告一個功能 { Console.WriteLine("Good bye"); } } } ``` ### Object(物件) 在 C# 中,object 是一個類型,也是所有其他類型的基底類型。每個類型(包括結構、類和基本類型)都隱式地繼承自 object 類型。 object 類型可以用來聲明變數、參數或返回值,這樣它們就可以接受任何類型的值。 object 類型還定義了一些通用的方法和屬性,例如 ToString()、Equals() 和 GetHashCode() 等,這些方法可以在所有類型的實例上調用。 總結來說,object 是所有其他類型的基底類型,可以用來聲明接受任何類型值的變數,但需要進行顯式的類型轉換才能進行具體的操作。 >需要注意的是,當將值從 object 類型轉換回具體類型時,如果轉換不合法,則會引發 InvalidCastException 異常。因此,在進行類型轉換時,應該先確保轉換是安全和有效的。 ```csharp= using System; namespace Exercise32_Object { class Program { static void Main(string[] args) { Human human1 = new Human();//建立一個Human的實例 Human human2 = new Human(); human1.name = "LW";//先利用Human這個類別裏面所定義好的類別來宣告 human1.age = 26; human2.name = "Molly";//先利用Human這個類別裏面所定義好的類別來宣告 human2.age = 29; human1.eat();//呼叫Human類別裏的功能 human1.sleep(); human2.eat();//呼叫Human類別裏的功能 human2.sleep(); } } class Human//建立一個類別 { public string name;//在宣告時竟然給予public讓外部的程式能夠讀取到這個類別的物件宣告方法 public int age; public void eat() { Console.WriteLine(name + " is eating"); } public void sleep() { Console.WriteLine(name + " is sleeping"); } } } /* LW is eating LW is sleeping Molly is eating Molly is sleeping */ ``` ### Extension Methods(擴展方法) 在 C# 中,你可以使用擴展方法(Extension Methods)為現有的類添加新的方法,而無需修改原始類的源碼。 範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { var rectangle = new Rectangle(5, 2); WriteLine("width is " + rectangle.Width); WriteLine("height is " + rectangle.Height); WriteLine("CalculateCircumference is " + rectangle.CalculateCircumference()); WriteLine("CalculateArea is " + rectangle.CalculateArea()); } } class Rectangle { public int Width; public int Height; public Rectangle(int width,int height) { Width = width; Height = height; } public int CalculateCircumference()//宣告一個method并且需要回傳值 { return 2 * Width + 2 * Height;//因爲在Rectangle這個類別裏面定義了Width和Height的來源所以無需在重新寫需要的參數 } public int CalculateArea()//若要被其他外部Class呼叫的話一樣要寫public { return Width * Height; } } } /* width is 5 height is 2 CalculateCircumference is 14 CalculateArea is 10 */ ``` ### Encapsulation(封裝) 封裝(Encapsulation)是面向對象編程(OOP)中的一個重要概念,它指的是將數據(屬性)和操作數據的方法(方法)包裝在一個單獨的單元(類)中,並對外部隱藏內部實現的細節。這種隱藏內部細節的方式,使得其他代碼只能通過公開的方法來訪問和操作對象的數據,同時不需要知道具體的實現細節。 以下是封裝的幾個主要原則和概念 1. **訪問修飾符**:在 C# 中,可以使用不同的訪問修飾符(public、private、protected 等)來控制類的成員(屬性和方法)的訪問權限。封裝的一個關鍵目標是通過將數據設為私有(private),只允許通過公開(public)的方法進行訪問,以確保外部代碼無法直接訪問內部數據。 2. **信息隱藏**: 封裝允許你將類的內部實現細節隱藏起來,只公開必要的操作接口。這樣可以有效降低代碼的耦合性,並提高代碼的可維護性和可讀性。 3. **數據保護**: 通過封裝,你可以確保數據在被訪問和修改時得到適當的保護。只有允許的方法能夠修改數據,從而減少了出錯的可能性。 4. **代碼組織**:封裝有助於將代碼組織成模塊化單元,從而讓你的應用程序結構更加清晰和易於管理。每個類可以擁有自己的成員,並定義自己的行為。 5. **信息抽象**:通過封裝,你可以隱藏實現細節,只暴露必要的方法,從而實現了一種信息的抽象。這讓用戶只需關注如何使用,而無需了解內部的工作細節。 使用封裝的例子 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { var rectangle = new Rectangle(5, 2); var calculator = new ShapeMeasurementCalculator();//宣告一個新的類別 WriteLine("width is " + rectangle.Width); WriteLine("height is " + rectangle.Height); WriteLine("CalculateCircumference is " + calculator.CalculateCircumference(rectangle)); WriteLine("CalculateArea is " + calculator.CalculateArea(rectangle)); } } class Rectangle//這個類別是用來儲存類別 { public int Width; public int Height; public Rectangle(int width,int height) { Width = width; Height = height; } } class ShapeMeasurementCalculator//在這裏建立一個新的類別 并且把功能類的函數給寫在該類別裏,透過呼叫Rectangle這個類別來呼叫參數 { public int CalculateCircumference(Rectangle rectangle)//宣告一個method并且需要回傳值 { return 2 * rectangle.Width + 2 * rectangle.Height;//因爲在Rectangle這個類別裏面定義了Width和Height的來源所以無需在重新寫需要的參數 } public int CalculateArea(Rectangle rectangle)//若要被其他外部Class呼叫的話一樣要寫public { return rectangle.Width * rectangle.Height; } } } /* width is 5 height is 2 CalculateCircumference is 14 CalculateArea is 10 */ ``` ### Constructors(建構子) 構造函數(Constructors)是一種特殊的方法,用於初始化類的新實例。它具有與類同名的方法名,並且沒有返回值類型。 以下是構造函數的一些重要特點: * 構造函數在創建類的新實例時自動調用。當使用 new 關鍵字創建一個類的實例時,相應的構造函數被調用。 * 構造函數可以用於初始化類的成員變量、屬性和其他狀態。 * 如果沒有定義任何構造函數,則編譯器將自動生成一個默認構造函數。默認構造函數不帶任何參數,並且不執行任何初始化操作。 * 構造函數可以擁有多個重載形式,即可以有不同的參數列表。這樣可以根據不同的需求來創建不同的初始化方式。 以下是一個使用構造函數的例子: ```csharp= class Person { public string Name { get; set; } public int Age { get; set; } // 定義帶有參數的構造函數 public Person(string name, int age) { Name = name; Age = age; } // 定義無參數的默認構造函數 public Person() { // 可以在構造函數中進行初始化操作 Name = "Unknown"; Age = 0; } } // 使用構造函數創建類的實例 Person person1 = new Person("John", 30); Person person2 = new Person(); ``` 以下是一個範例 ```csharp= using System; namespace Exercise33_Constructors { class Program { static void Main(string[] args) { Car car1 = new Car("Ford","Mustang",2020,"Red");//建立實例并且賦予預設值 Car car2 = new Car("Chevy", "Corvette", 2022, "Blue"); car1.Drive(); car2.Drive(); } } class Car//建立一個類別 { //宣告變數 string make; string model; int year; string color; public Car(string make,string model,int year,string color)//初始化參數 可以使用和Class一樣的名稱 { this.make = make; this.model = model; this.year = year; this.color = color; } public void Drive() { Console.WriteLine($"You drive the {make} {model}"); } } } /* You drive the Ford Mustang You drive the Chevy Corvette */ ``` 建立類別的另一個例子 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp8 { class Program { static void Main(string[] args) { // var rectangle = new Rectangle(2, 5);//如果在沒設計好建構子所需的參數的話,它只會寫入預設的值。因爲我在類別一開始只有宣告兩個變數名稱,并沒賦予任何值。所以這行會報錯。原因是它不需要賦予兩個新的參數值。 // var rectangle = new Rectangle();//這樣宣告的話就能夠使用因爲我們在類別裏沒有需要放入參數。 var rectangle = new Rectangle(5, 2);//如果在建構子裏有提前宣告需要放入什麽參數的話,在引用的時候會看到提示。 Console.WriteLine("width is " + rectangle.Width);//請注意,如果想從其他Class呼叫類別的話,記得在該類別裏的變數前面添加public,不然的話其他類別會無法呼叫該參數 Console.WriteLine("height is " + rectangle.Height); } } class Rectangle//建立一個類別 { public int Width;//定義兩個值 一個是高度一個是寬度并且設定為public可以讓其他類別去使用這兩個變數。 public int Height;//如果是要定義private的話只要在變數前面放底綫_即可 public Rectangle(int width,int height)//建立一個建構子,建構子的名字可以跟類別一樣并且需要放入兩個參數 { Width = width;//把類別裏的參數和建構子裏所需要的參數 Height = height; } } } /* width is 5 height is 2 */ ``` ### Constructor Overloading(建構函式多載) 建構函式多載(Constructor Overloading)是一種物件導向程式設計中的概念,它允許在同一個類中定義多個不同參數列表的建構函式。這樣做的目的是讓使用者在創建物件時有多種不同的選擇,以便根據不同情況來初始化物件的屬性。 建構函式多載的主要特點是同一個類可以有多個不同參數數量或類型的建構函式,每個建構函式可以在初始化過程中進行不同的操作。這提供了靈活性,讓你可以使用不同的初始化方式創建相同類型的物件。 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { } } class Media { private string _patienName; private DateTime _date; public Media(string patienName,DateTime date)//這個建構函式的目的是讓使用者能夠直接指定病人姓名和日期來初始化 Media 物件。 { _patienName = patienName; _date = date; } public Media(string patienName) : this(patienName, 7)//是一個簡化版本的建構函式。它只接受病人姓名(patienName)作為參數,然後使用 this 關鍵字調用了第一個建構函式,並將 DateFromNow 設置為 7。這個版本的建構函式使使用者可以只提供病人姓名,而日期將默認為 7 天後。 { } public Media(string patienName,int DateFromNow)//接受病人姓名和日期相對於當前日期的天數作為參數。它使用 DateTime.Now.AddDays(DateFromNow) 來計算指定天數後的日期,並初始化 _patienName 和 _date 屬性。 { _patienName = patienName; _date = DateTime.Now.AddDays(DateFromNow); } } } ``` ### Static(靜態) 是一個關鍵字,用於聲明靜態成員或靜態類。 靜態成員有以下特點 * 靜態成員是與類關聯而不是與類的實例關聯的成員。 * 靜態成員屬於類本身,而不是屬於類的個別實例。 * 可以直接通過類名訪問靜態成員,而不需要先創建類的實例。 * 靜態成員在程序執行期間只有一份,並且在程序執行期間保持不變。 * 靜態成員可以是靜態方法、靜態屬性、靜態字段等。 * 靜態成員在內存中被共享,可以被類的所有實例訪問。 靜態類 * 靜態類是一個特殊類型的類,它只包含靜態成員,且無法實例化。 * 靜態類可以包含靜態方法、靜態屬性、靜態字段等。 * 靜態類主要用於提供一組相關的工具方法或常用功能,可以直接通過類名訪問這些方法或功能,而不需要先創建類的實例。 使用靜態成員和靜態類的好處是: * 可以在不創建類的實例的情況下訪問和使用它們。 * 可以在整個應用程序中共享和重用這些成員,而不需要為每個實例創建獨立的副本。 ```csharp= using System; namespace Exercise34_Static { class Program { static void Main(string[] args) { Car car = new Car("Mustang"); Car car2 = new Car("Corvette"); Car car3 = new Car("Lambo"); Console.WriteLine(Car.NumberOfCars);//呼叫類別裏的變數 Car.startRace(); } } class Car { string model; public static int NumberOfCars;//把這個方式變成靜態的類別 public Car(string model) { this.model = model; NumberOfCars++;//每次新增一個Car的實例就會+1 } public static void startRace() { Console.WriteLine("The Race has begun!"); } } } /* 3 The Race has begun! */ ``` ### Overloading Constructor(多載建構子) Overloading constructor 是指在一個類中定義多個具有不同參數列表的構造函數。每個構造函數可以接受不同數量和類型的參數,從而提供了創建對象的不同方式。 當你在一個類中定義了多個構造函數時,它們可以根據參數的不同來區分彼此,從而讓你可以使用不同的方式來初始化對象。這使得你可以根據不同的情況選擇最合適的構造函數來創建對象。 使用構造函數重載的好處在於可以根據不同的需求提供不同的初始化方式。例如,對於一個類,可以根據不同的參數列表提供不同的默認值,或者允許用戶根據自己的需求傳遞不同的參數 ```csharp= using System; namespace Exercise35_Overloading_Constructor { class Program { static void Main(string[] args) { Pizza pizza = new Pizza("stuffed curst", "red sauce", "mozzarella");//在建立實例時可以透過Class裏不同的參數類別來設定初始值。雖然在Pizza裏有兩個功能都一樣叫Pizza,可是在預設值兩者所需的數值都不一樣。 } } class Pizza { string bread; string sauce; string cheese; string topping; public Pizza(string bread,string sauce,string cheese,string topping)//建立一個功能名叫Pizza裏面需要輸入4個參數 { this.bread = bread; this.sauce=sauce; this.cheese = cheese; this.topping = topping; } public Pizza(string bread, string sauce, string cheese)//建立另一個功能名字一樣Pizza裏面只需要輸入3個參數 { this.bread = bread; this.sauce = sauce; this.cheese = cheese; } } } ``` ### Inheritance(繼承) 當談到繼承(Inheritance)時,主要重點如下: 1. 繼承允許一個類別從另一個類別中繼承屬性和行為。 2. 衍生類別(子類別)可以訪問和使用基礎類別(父類別)的成員,包括欄位、屬性和方法。 3. 繼承提供了代碼重用的能力,因為衍生類別可以使用基礎類別的已實現功能而無需重複編寫。 4. 衍生類別可以擴展、修改或重寫基礎類別的成員,以適應特定的需求。 5. 繼承支持多級繼承,即類別可以作為其他類別的衍生類別,形成類別的層次結構。 繼承是物件導向程式設計中的重要概念,它幫助組織和結構化程式碼,提高代碼的可重用性和擴展性。通過繼承,可以建立類別之間的關係,使代碼更易於理解、維護和擴展。 ```csharp= using System; namespace Exercise36_Inheritance { class Program { static void Main(string[] args) { Car car = new Car(); Bicycle bicycle = new Bicycle(); Boat boat = new Boat(); Console.Write(car.speed);//繼承了的類別后可以呼叫Vehicle裏的功能 Console.Write(car.wheel); car.go(); Console.Write(bicycle.speed); Console.Write(bicycle.wheel); bicycle.go(); Console.Write(boat.speed); Console.Write(boat.wheel); boat.go(); } } class Vehicle { public int speed; public void go() { Console.WriteLine("This vehicles is moving!"); } } class Car : Vehicle //新建一個類別Car 繼承Vehicle { public int wheel = 4; } class Bicycle : Vehicle //新建一個類別Bicycle 繼承Car { public int wheel = 2; } class Boat : Vehicle //新建一個類別Boat 繼承Bicycle { public int wheel =0; } } /* 04This vehicles is moving! 02This vehicles is moving! 00This vehicles is moving! */ ``` ### Abstract Classes(抽象類別) 抽象類別(Abstract Classes)是一種特殊類型的類別,在物件導向程式設計中具有以下特點: 1. 抽象類別無法被實例化,也就是無法直接建立該類別的物件。 2. 抽象類別通常用作基礎類別,用於定義一組相關的類別的共同特徵和行為。 3. 抽象類別可以包含抽象成員(方法、屬性、事件等),這些成員只有聲明而沒有實作。 4. 衍生類別(子類別)必須實作所有抽象類別中聲明的抽象成員,以便實例化衍生類別的物件。 5. 抽象類別可以包含具體(非抽象)的成員,這些成員具有實際的實作。 6. 抽象類別提供了一種模板或藍圖,供衍生類別繼承和擴展使用。 抽象類別的主要目的是提供一個共享的基礎結構,以便衍生類別可以繼承並擴展該結構。它提供了一種抽象化的方式來描述相關類別的共同特徵和行為,同時也要求衍生類別實作必要的抽象成員。抽象類別在設計和建立大型程式時非常有用,可以幫助組織程式碼並確保一致性和可維護性。 ```csharp= using System; namespace Exercise37_Abstract_Classes { class Program { static void Main(string[] args) { Car car = new Car(); Bicycle bicycle = new Bicycle(); Boat boat = new Boat(); //Vehicles vehicles = new Vehicles(); //會報錯 } } abstract class Vehicles//Vehicle裏的類別不適合用來創建實例 所以要透過abstract的方式來建立 { public int speed = 0; public void go() { Console.WriteLine("This car is moving"); } } class Car : Vehicles { public int wheels = 4; int maxspeed = 500; } class Boat : Car { public int wheels = 0; int maxspeed = 100; } class Bicycle: Boat { public int wheels = 2; int maxspeed = 50; } } ``` ### Array Of Objects 陣列(Array)是一種能夠在單一變數中儲存多個相同類型的元素的資料結構。而「物件陣列」(Array of Objects)則是指陣列中儲存的元素為物件(Object)。 在 C# 中,我們可以建立物件陣列來儲存多個物件,每個物件都屬於同一個類型或其衍生類型。這允許我們在單一陣列中存儲和操作多個相關物件。 ```csharp= using System; namespace Exercise38_Array_of_objects { class Program { static void Main(string[] args) { Car[] garage = new Car[3]; //建立一個屬於Car類別的陣列 并且設定大小為3 Car car1 = new Car("Mustang"); Car car2 = new Car("Corvette"); Car car3 = new Car("Lambo"); garage[0] = car1; garage[1] = car2; garage[2] = car3; foreach(Car car in garage) { Console.WriteLine(car.model);//如果要從特定的類別讀出相關陣列的值的話在變數名稱[索引]后要加入一個.相關類別 不然會讀不出來 } } } class Car { public string model; public Car(string model) { this.model = model; } } } /* Mustang Corvette Lambo */ ``` ### Object As Argument(物件參數傳遞) 在C#中,可以將物件作為參數傳遞給方法。這意味著您可以將一個物件的實例傳遞給方法,以便方法可以使用該物件的屬性和方法。 當您將物件作為參數傳遞給方法時,方法可以直接訪問和修改物件的狀態,或者調用物件的方法。這使得您可以在方法中操作和處理不同的物件,以實現更靈活和可重用的程式設計。 通過將物件作為參數傳遞給方法,我們可以在不同的方法之間共享和操作物件的狀態和行為,從而實現更靈活和可重用的程式設計。 ```csharp= using System; namespace Exercise39_Object_as_argument { class Program { static void Main(string[] args) { Car car1 = new Car("Mustang", "Red"); Car car2 = copy(car1); Console.WriteLine(car2.color + " " + car2.model); } public static Car copy(Car car)//創建一個新的類別,需要輸入的參數是透過其他類別去設置 { return new Car(car.model,car.color); } } class Car { public string model; public string color; public Car(string model,string color) { this.model = model; this.color = color; } } } //Red Mustang ``` ### Method Overriding(方法覆寫) 方法覆寫(Method Overriding)是物件導向程式設計中的一個概念,它允許子類別重新定義父類別中已存在的方法,以適應自己的特定需求。 當子類別繼承自父類別時,它可以使用相同的方法名稱並且具有相同的方法簽名(即相同的參數列表),來重新定義父類別中的方法。這樣子類別就可以對該方法進行自定義的實現,而不必使用父類別的實現。 使用方法覆寫,可以實現多態性(Polymorphism)的概念。多態性是指在不同的物件類型下,相同的方法名稱可以產生不同的行為。當使用父類別的引用指向子類別的實例時,可以根據實際的物件類型來決定使用哪個類別中的方法。 ```csharp= using System; namespace Exercise40_Method_Overriding { class Program { static void Main(string[] args) { Dog dog = new Dog(); Cat cat = new Cat(); dog.Speak(); cat.Speak(); } } class Animal { public virtual void Speak()//virtual:表示該方法可以被子類別覆寫,即子類別可以重新定義這個方法的實現。 { Console.WriteLine("The animals goes *brrrr*"); } } class Dog : Animal { public override void Speak()//override: 表示該方法覆寫了父類別中的虛擬方法。 { Console.WriteLine("The dog goes *woof*"); } } class Cat : Animal { public override void Speak()//override: 表示該方法覆寫了父類別中的虛擬方法。 { Console.WriteLine("The cat goes *meow*"); } } } /* The dog goes *woof* The cat goes *meow* */ ``` ### ToString Method ToString 是 C# 中的一個方法,它用於將對象轉換為其對應的字符串表示形式。 當在 C# 中使用 ToString 方法時,它會返回一個表示該對象的字符串。默認情況下,ToString 方法返回對象的完全限定類型名稱。 然而,可以通過在類別中覆寫 ToString 方法,自定義對象的字符串表示形式。這在需要將對象轉換為字符串以進行顯示、日誌記錄、調試等場景下非常有用。 ```csharp= using System; namespace Exercise41_ToString_method { class Program { static void Main(string[] args) { Car car = new Car("Chevy","Corvette",2021,"Red"); Console.WriteLine(car.ToString());//第一種寫法 Console.WriteLine(car);//第二種寫法 } } class Car { string make; string model; int year; string color; public Car(string make,string model,int year,string color) { this.make = make; this.model = model; this.year = year; this.color = color; } public override string ToString()//overide ToString功能 { return "This is a " + make + " " +model;//回傳輸出 } } } //This is a Chevy Corvette //This is a Chevy Corvette ``` ToString 方法在 System.Object 類別中被定義為虛擬方法,可以在子類別中被覆寫。 當我們使用 Console.WriteLine 或其他類似的方法來打印 Car 對象時,如果沒有覆寫 ToString 方法,將會打印出該對象的類別名稱。但是,通過覆寫 ToString 方法,我們可以定義自己的字符串表示形式,以便更有意義地描述該對象。 ### Polymorphism(多型性) 當涉及到多型性時,以下是一些重點條列: * 多型性允許使用相同的程式碼處理不同類型的物件。 * 父類別的變數可以指向子類別的實例,並且可以使用父類別的變數來調用子類別中定義的方法和屬性。 * 多型性提供了程式碼的靈活性和可擴展性,因為它允許替換和擴展類別而無需修改使用該類別的程式碼。 * 多型性通常與繼承和方法重寫(override)一起使用,子類別可以重寫父類別中的方法,並根據需要定義自己的實現。 * 在運行時,根據物件的實際類型,將調用對應的方法。 * 多型性有助於實現抽象和彈性的程式設計,並支持設計模式如策略模式、工廠模式等。 * C#中的多型性可以通過關鍵字 override 和 virtual 來實現,virtual 用於父類別中的方法,override 用於子類別中對父類別方法的重寫。 ```csharp= using System; namespace Exercise42_Polymorphism { class Program { static void Main(string[] args) { Car car = new Car(); Bicycle bicycle = new Bicycle(); Boat boat = new Boat(); //Car[] vehicless = { car, bicycle, boat };//會報錯是因爲Car是一個獨立的Class Bicycle以及Boat不包含在這個Class裏 所以沒辦法用陣列的方式放在一起 Vehicle[] vehicles = { car, bicycle, boat };//而Vehicle可以的原因是因爲這三個列別都繼承了Vehicle的Class foreach (Vehicle vehicle in vehicles)//由於在Vehicle裏都有Go功能,所以可以透過foreach的方式讀取出來,在讀取的時候一定要讓確保以下所有類別的名字都一樣才可以這樣去執行功能 { vehicle.Go(); } } } class Vehicle { public virtual void Go()//建立一個virtual的功能讓以下三個類別都可以透過override去覆寫 { } } class Car : Vehicle { public override void Go()//覆寫Vehicle裏的Go功能 { Console.WriteLine("The Car is moving"); } } class Bicycle : Vehicle { public override void Go()//覆寫Vehicle裏的Go功能 { Console.WriteLine("The Bicycle is moving"); } } class Boat : Vehicle { public override void Go()//覆寫Vehicle裏的Go功能 { Console.WriteLine("The Boat is moving"); } } } /* The Car is moving The Bicycle is moving The Boat is moving */ ``` ### Interface(界面) 介面(Interface)是在面向對象程式設計中一個重要的概念,以下是關於介面的重點條列: * 介面定義了一組方法、屬性和事件的契約,而不包含任何實現細節。它定義了一個類型應該具備的成員,但不提供具體的實現。 * 介面提供了一種合約,表示實現該介面的類別必須實現指定的成員,以確保一致性和互換性。 * 類別可以實現一個或多個介面,通過實現介面定義的成員來滿足介面的合約。 * 介面支持多重繼承,一個類別可以同時實現多個介面。 * 介面可以用於實現多型性,使得可以使用相同的程式碼處理不同的物件,只要它們實現了相同的介面。 * 介面的成員是隱式公開的,不需要使用關鍵字 public 來修飾。 * C#中使用關鍵字 interface 定義介面,並使用 class 關鍵字來實現介面。 * 介面可以繼承其他介面,通過這種方式可以建立更大型的介面階層結構。 介面是實現多態性和促進代碼重用的強大工具。它提供了一種抽象的機制,使得程式設計師可以定義一組共享的合約,並在不同的類別中實現這些合約。這樣,當多個類別實現同一介面時,它們就可以在程式中被一致地使用。 ```csharp= using System; namespace Exercise43_Interface { class Program { static void Main(string[] args) { Rabbit rabbit = new Rabbit(); Hawk hawk = new Hawk(); Fish fish = new Fish(); rabbit.Flee();//呼叫rabbit裏Flee的功能 hawk.Hunt();//只能呼叫自己繼承Interface功能無法呼叫Flee fish.Flee();//由於Fish已經繼承兩種Interface所以可以呼叫Flee以及Hunt功能 fish.Hunt(); } } interface IPrey//獵物 { void Flee();//宣告一個Flee逃跑的功能 可是不實作方法 實作功能部分留給Class } interface IPredator//獵人 { void Hunt(); } class Rabbit : IPrey //繼承IPrey裏的功能 { public void Flee()//宣告一個一樣的Flee功能 { Console.WriteLine("The Rabbit runs away!"); } } class Hawk : IPredator { public void Hunt() { Console.WriteLine("The hawk is searching for food!"); } } class Fish:IPrey ,IPredator//可以繼承多種Interface { public void Flee() { Console.WriteLine("The fish swims away!"); } public void Hunt() { Console.WriteLine("The fish is searching smaller fish!"); } } } /* The Rabbit runs away! The hawk is searching for food! The fish swims away! The fish is searching smaller fish! */ ``` ### Lists(列表) List 是 C# 中的一個動態陣列(dynamic array)類型,它提供了方便的方法來管理和操作集合元素。以下是關於 List 的重點概括: * List 是 System.Collections.Generic 命名空間下的類型,需要使用 using * System.Collections.Generic 引用。 * List 可以儲存相同類型的元素,並動態調整大小以容納新增或刪除的元素。 * List 提供了多種方法來添加、刪除、查找和排序元素,例如 Add、Remove、Contains 和 Sort 等。 * List 的索引從 0 開始,可以使用索引訪問和修改特定位置的元素。 * List 可以使用 Count 屬性獲取元素的數量。 * List 是泛型類型,因此需要在建立 List 實例時指定元素的類型。例如 List<int> 表示一個整數型的 List。 * 可以使用 foreach 循環來遍歷 List 中的元素。 * List 是可變的,可以動態調整大小,自動擴展或收縮以適應元素的添加或刪除。 * 可以使用 Capacity 屬性獲取或設定 List 的容量,以提前分配空間,以減少重新分配的次數,提高效能。 使用 List 可以方便地處理和管理集合數據,它提供了豐富的方法和功能,適用於各種場景,例如存儲和操作集合、實現資料結構等。 ```csharp= using System; using System.Collections.Generic;//要使用List 一定要引用這個命名空間 namespace Exercise44_Lists { class Program { static void Main(string[] args) { //使用List的方法 List<string> food = new List<string>();//要建立list的方法是List<資料形態> 變數名字=new List<資料形態>(); food.Add("Pizza");//透過Add的方式新增元素進去這個列表裏 food.Add("Hamburger"); food.Add("hotdog"); food.Add("fries"); // Console.WriteLine(food[0]);//單獨輸出某一個元素只要指出相對應的索引即可 food.Remove("hotdog");//移除某一個元素 food.Insert(0, "Sushi");//插入一個新的元素 總共要賦予兩個值,第一個是要插入的位置,第二個是元素的名稱 Console.WriteLine(food.Count);//可以透過Count的功能來計算出目前這個列表内有多少個元素。 Console.WriteLine(food.IndexOf("Hamburger"));//IndexOf是用於查找指定元素在列表(List)或字串中的索引位置的方法。 Console.WriteLine(food.LastIndexOf("fries"));//LastIndexOf是用於查找指定元素在列表(List)或字串中的最後一次出現的索引位置的方法。如果第0個位子出現而後續還有出現相同的值的話則會以最後一個值爲主。 Console.WriteLine(food.Contains("Pizza"));//Contains是用於檢查列表(List)或字串是否包含指定元素或字串的方法。會回傳一個布林值 //food.Sort();//排序 //food.Reverse();//反向排序 //food.Clear();//清空列表中所有的值 string[] foodArray = food.ToArray();//把list轉成Array的方式是 資料形態[]變數名字=列表名字.ToArray(); Console.WriteLine(foodArray.GetType());//用來輸出foodArray是什麽資料形態 foreach (string items in foodArray) { Console.WriteLine(items); } /* string[] food = new string[3];//一般傳統的Array在設計的時候就必須要先賦予大小,若突然要新增東西的話變得很麻煩 food[0] = "Pizza"; food[1] = "hamburger"; food[2] = "noodle"; foreach (string items in food) { Console.WriteLine(items); } */ } } } /* 4 2 3 True System.String[] Sushi Pizza Hamburger fries */ ``` ### List Of Objects 使用 List<T> 創建一個物件的列表,其中 T 是你想要存儲的物件類型。以下是一個示例: ```csharp= using System; using System.Collections.Generic; namespace Exercise45_List_Of_Objects { class Program { static void Main(string[] args) { List<Player> players = new List<Player>();//建立一個List 透過Player這個Object Player player = new Player("Chong"); Player player2 = new Player("Lit"); Player player3 = new Player("Wei"); players.Add(player); players.Add(player2); players.Add(player3); foreach(Player Player in players) { Console.WriteLine(Player);//如果不透過overide ToString的話 無法正常顯示所有名字 } } } class Player { string name; public Player(string name) { this.name = name; } public override string ToString() { return name; } } } /* Chong Lit Wei */ ``` ### Getter & Setter Getter 和 Setter 是用於訪問和設置類的屬性(成員變量)的方法。它們通常被用於封裝類的內部數據,以便控制對這些數據的訪問。 Getter 是一個方法,用於獲取屬性的值。它返回屬性的當前值,並通常以類似於讀取變量的方式使用。 Setter 是一個方法,用於設置屬性的值。它接受一個值作為參數,並將該值分配給屬性。它通常以類似於寫入變量的方式使用。 Getter 和 Setter 方法的命名通常遵循一些常見的慣例,例如 GetPropertyName 和 SetPropertyName。其中,PropertyName 是要訪問或設置的屬性的名稱。 ```csharp= using System; namespace Exercise46_Getter_And_Setter { class Program { static void Main(string[] args) { Car car = new Car(400); car.Speed = 10000000; Console.WriteLine(car.Speed); } } class Car { private int speed; public Car(int speed) { Speed = speed; } public int Speed { get { return speed; }//返回 Speed 屬性的當前值。在這個例子中,Getter 方法的實現只是返回 speed 的值。 set {//Setter 方法(set)用於設置 Speed 屬性的值。當給屬性賦值時,Setter 方法會接收一個參數 value,代表新的值。在這個例子中,Setter 方法的實現檢查輸入的值是否大於 500。如果是,則將 speed 設置為 500,以限制速度的上限。否則,將 speed 設置為輸入的值。 if (value > 500) { speed = 500; } else { speed = value; } } } } } //500 ``` ### Auto Implemented Properties(自動實作屬性) 自動實作屬性(Auto-implemented Properties)是 C# 中的一種簡化屬性定義的語法形式。它允許您在不顯式定義私有變量的情況下聲明和使用屬性。 傳統的屬性定義需要您定義一個私有變量來儲存屬性的值,然後通過 Getter 和 Setter 方法來訪問和設置該變量的值。這樣的定義需要額外的程式碼來管理私有變量,並且可能導致程式碼冗長。 使用自動實作屬性,您只需聲明屬性的類型、名稱和訪問修飾詞,而無需定義私有變量和顯式的 Getter 和 Setter 方法。C# 編譯器將自動為您生成相應的私有變量和 Getter/Setter 方法。 ```csharp= using System; namespace Exercise47_Auto_Implemented_Properties { class Program { static void Main(string[] args) { Car car = new Car("Porsche"); Console.WriteLine(car.Model); } } class Car { string model; public string Model { get; set; }//一種自動實作屬性的簡化語法。這個語法讓你可以快速定義一個屬性,同時隱藏了屬性的私有儲存欄位和其存取方法。 //在這個例子中,我們定義了一個 Model 屬性,它是一個 string 型別的屬性。這個屬性具有自動實作,意味著編譯器將自動為該屬性生成相應的儲存欄位和存取方法。 public Car(string model) { Model = model;//在 Car 類別的建構函式中,我們通過將傳入的 model 參數賦值給屬性 Model,來初始化 Car 物件的車型。 } } } //Porsche ``` ### Enums(列舉) Enums(列舉)是 C# 中的一種特殊類型,用於定義一組命名的常數值。它們提供了一種方便的方式來表示一組相關的常數,並可以將這些常數用作變量的值。 ```csharp= using System; namespace Exercise48_Enums { class Program { static void Main(string[] args) { string name = PlanetRadius.Earth.ToString();//呼叫PlanetRadius裏面的Earth元素并且把該值轉成字串 int radius = (int)PlanetRadius.Earth;//呼叫PlanetRadius裏面的Earth元素并且把該值轉成數字 double volume = Volume(PlanetRadius.Earth);//用static的方法實作的功能不需要在做實例 直接呼叫即可 Console.WriteLine(Planets.Pluto +" is a planet");//呼叫Planets裏的Pluto元素,它會回傳的是Pluto這個名字而不是數值或者索引,透過ToString也是一樣會回傳字串 Console.WriteLine(Planets.Mercury + "is planet # " + (int)Planets.Mercury);//若要輸出的是列舉裏的位置則要增加(int)强制轉型 Console.WriteLine(Planets.Pluto + "is planet # " + (int)Planets.Pluto); Console.WriteLine("planet: " + name); Console.WriteLine("Radius: " + radius); Console.WriteLine("Volume: " + volume); } public static double Volume(PlanetRadius radius) { double volume = (4.0 / 3.0) * Math.PI * Math.Pow((int)radius,3); return volume; } } enum Planets//建立一個星球的列舉 { //name=integer 可以一開始就設定每一個值的初始值 Mercury=1, Venus=2, Earth=3, Mars=4, Jupyter=5, Saturn=6, Uranus=7, Neptune=8, Pluto=9//把9大行星都寫進來 } enum PlanetRadius//行星半徑 { Mercury = 1865, Venus = 2488, Earth = 3986, Mars = 4598, Jupyter = 5878, Saturn = 6862, Uranus = 7826, Neptune = 8629, Pluto = 9568 } } /* Pluto is a planet Mercuryis planet # 1 Plutois planet # 9 planet: Earth Radius: 3986 Volume: 265277546629.2339 */ ``` ### Generics 泛型(Generics)是 C# 中的一個重要概念,它允許在類別或方法的定義中使用參數化的類型。通過使用泛型,我們可以在編譯時期將具體的類型作為參數傳遞,提供更靈活和可重用的程式碼。 泛型的主要優點是它可以提供類型安全性和可靠性,並減少類型轉換的需要。它還可以幫助我們編寫更通用和彈性的程式碼,因為我們可以在不同的類型上重用相同的程式碼邏輯。 在 C# 中,泛型可以應用於類別、結構、介面、方法等各種成員的定義。 以下是一些常見的泛型用法: 1. 泛型類別(Generic Class):使用 <T> 表示泛型參數。 2. 泛型方法(Generic Method):在方法定義中使用 <T> 表示泛型參數。 3. 泛型介面(Generic Interface):使用 <T> 表示泛型參數。 4. 泛型約束(Generic Constraint):使用 where 關鍵字對泛型參數進行約束,限制它應該是某個特定類型或滿足某些條件。 ### Expression-bodied methods 是 C# 中的一種簡潔的語法,用於定義單行方法的實現。這種語法使得定義簡單方法變得更加簡潔和易讀。 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { Caculator caculator = new Caculator(); Console.WriteLine("Add:"+caculator.Add(5, 3));//兩者功能都一樣能執行,只是可以縮減不必要的行數 Console.WriteLine("Sub:"+caculator.Subtract(5, 3)); } } class Caculator//建立一個Class名為計算機 { public int Add(int a,int b)//傳統寫法是以return的方式回傳值 { return a + b; } public int Subtract(int a, int b) => a - b;//Expression-bodied methods是使用=>的方式來進行計算并且直接回傳值 } } /* Add:8 Sub:2 * ``` ### This Method 在 C# 中,this 是一個關鍵字,用於引用當前對象(實例)的引用。它用於在類的成員(方法、屬性、字段等)中區分當前對象的成員和參數名稱或局部變數名稱。 使用 this 關鍵字有以下幾個用途: 1. **區分成員與參數**:當方法或構造函數的參數名稱與類的成員名稱相同時,使用 this 可以區分這兩者,使編譯器能夠識別你要引用的是類的成員。 2. **在構造函數中調用其他構造函數**: 在構造函數中,你可以使用 this 關鍵字來調用同一類中的其他構造函數。這種情況下,被調用的構造函數必須位於 this 語句之前。 區分成員與變數範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { } } class Person//建立一個類別 { private string name;//宣告一個private的變數名為name public Person(string name)//建立一個不用回傳值的方法 { this.name = name;//因爲這裏的左邊的name和這個方法需要的參數name名字都一樣,所以要放一個this來區分兩者的區別,左邊為我們要使用這個類別裏的name也就是private } public void Introduce()//建立一個需要回傳值的方法 { Console.WriteLine($"My name is {this.name}");// 使用 this 來引用類的成員 } } } ``` 在構造函數中調用其他構造函數範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { } } class Student//定義了一個 Student 類,這個類具有三個屬性:Name、Age 和 School { public string Name { get; set; } public int Age { get; set; } public string School { get; set; } public Student(string name, int age, string school) //第一個建構函數接受三個參數,分別是姓名、年齡和學校名稱。它將這些參數分別賦值給 Name、Age 和 School 屬性。 { Name = name; Age = age; School = school; } public Student(string name, int age) : this(name, age, "Unknown School") //第二個建構函數接受姓名和年齡作為參數,然後使用 this 關鍵字調用了第一個建構函數,並將學校名稱設置為 "Unknown School"。這樣,使用者只需提供姓名和年齡,學校名稱將默認為 "Unknown School"。 { } public Student(string name) : this(name, 0) //第三個建構函數接受姓名作為參數,然後使用 this 關鍵字調用了第二個建構函數,將年齡設置為 0。這樣,使用者只需提供姓名,年齡將默認為 0。 { } public void DisplayInfo() { Console.WriteLine($"Name: {Name}, Age: {Age}, School: {School}"); } } } ``` ### Optional parameters(可選參數) 是 C# 中的一個功能,它允許你在方法或建構函式的定義中指定參數的默認值。這樣,當你呼叫這個方法或建構函式時,如果你沒有提供該參數的值,系統會使用預設的值。 可選參數的使用使得方法和建構函式的呼叫更加靈活,可以省略部分參數,而不需要為每個參數都傳遞值。 可選參數的範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { Calculator calculator = new Calculator(); int result1 = calculator.Add(5);//只給一個參數 int result2 = calculator.Add(5, 9);//給兩個參數 Console.WriteLine("result1=" + result1); Console.WriteLine("result2=" + result2); } } class Calculator { public int Add(int a, int b = 5) => a + b;//b 是可選參數,默認值為 5 } } /* result1=10 result2=14 */ ``` ### Object initializers(物件初始化) 物件初始化器(Object initializers)是一種用於初始化物件的簡化語法。在 C# 中,使用物件初始化器,你可以在創建物件的同時設置其屬性的初始值。 物件初始化範例 ```csharp= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using static System.Console; namespace ConsoleApp8 { class Program { static void Main(string[] args) { var Person = new Person()//參數初始化 { Name = "Chong", YearOfBirth = 1997 }; string name = Person.Name;//讀取參數的值 WriteLine(name);//輸出 } } class Person { public string Name { get; set; }//該屬性用於存儲人的名字 public int YearOfBirth { get; set; }//用於存儲出生年份 } } /* Chong */ ``` ### Linq的筆記->由於本記事本已經即將寫滿因此請點擊一下網址前往另一個記事本 https://hackmd.io/JMiYOrfySVuqkSJLRHhFHA?both