###### tags: `C#` `學習筆記` # C# 學習筆記 | 基礎 ## 知識 ### 輸出 ```csharp! Console.WriteLine(); // 輸出,換行 Console.Write(); // 輸出,不換行 ``` ### 作用域 變數只在 **{}** 生效 ```csharp! int a = 10; if(true) { int b = 20; } Console.WriteLine(a); // 10 Console.WriteLine(b); // 報錯 ``` ### 流程控制 ```csharp! //----- if if(<boolean_expression>) { statement(s); } else { statement(s); } //----- switch switch(<expression>) { case <constant-expression>: statement(s); break; case <constant-expression>: statement(s); break; default : /* 可選的 */ statement(s); break; } ``` ### 迴圈 ```csharp! //----- for for( init; condition; increment ) { statement(s); } //----- while while(<condition>) { statement(s); } //----- do while,一定先執行一次 do { statement(s); } while(<condition>) ``` ## 變數 ![](https://hackmd.io/_uploads/r1cuhfoUh.jpg) ### 強轉換 ```csharp! string str = "20"; int num = 20; //----- 轉換為 int int a = (int)str; int b = Convert.ToInt32(str); int c = int.Parse(str) //----- 轉換為 string string str = num.ToString(); ``` ### dynamic 動態 在聲明時會以賦予值類型來決定是什麼類型 ```csharp! dynamic a = 20; dynamic b = "20"; dynamic c; c = b + a; Console.WriteLine(a + 20); // 40 Console.WriteLine(b + 20); // 2020 Console.WriteLine(c); // 2020 ``` ### const | readonly `const` 和 `readonly` 的很相似,都是不能更改的變數 `const` 更加嚴格,他在聲明後就必須賦值, ```csharp! const double PI = 3.14; const int a = 20; // 會報錯 ``` 與之相比,`readonly` 可以先聲明,之後再賦值,但要注意的是 readonly 只能在構造函數(建構子)中賦值,不能在一般函數內賦值 ```csharp! internal class Airplane : IFly { private readonly int A; public Airplane(int a) { A= a; } public void Fly() { Console.WriteLine("飛機起飛了"); A = 20; // 會報錯 } } ``` ## String ### "" ```csharp! 1. string str = "c:\\file\\program"; // 特殊字符必須使用反斜線 2. string str = @"c:\file\program"; // 可以使用反斜線 3. string str = $"我的名字是{name}"; // 可以串接 ``` ### 常用函數 ```csharp! string web = "www.google.com"; string str = " Hi I am Zeke. " str.ToLower() // 全轉換大寫 str.ToUpper() // 全轉換小寫 str.Trim() // 修剪前後空白 str.CompareTo(web) // 0==true, 1==false str.Replace("ek", "a")) // replace all str.Substring(0, 2) // " H" 切頭切尾 web.Split(".") // ["www", "google", "com"] web.IndexOf(".") // 3 web.IndexOfAny(new char[] { 'z', 'g' }) // 搜索index,沒有就接續後面陣列的數字 web.Insert(0, "???") // ???www.google.com //----- CopyTo() char[] cArr = new char[10]; str.CopyTo(1, cArr, 1, 4); // 複製目標第1索引開始共4個char,到cArr第1索引 // [' ', 'H', 'i', ' ', 'I'] //----- 使用 String class int c = 2; int d = 8; string.Concat(web, str) // a + b, www.google.com Hi I am Zeke. string.Format("{0} + {1} = {2}", c, d, c + d) //2 + 8 = 10 string.Format("{0:C}", d)); // c 使用貨幣,NT$8.00 string.Format("{0:F2}", 33.2259) // f(n) 保留後面小數共n位,33.23 string.Format("{0:P}", 0.25259) // 百分比,25.26% ``` ### StringBuilder 一般的**string**是儲存在靜態儲存區中,更改過後會新增新的字串,不會對原來的數據進行變化,而是返回更改過後的字串 string builder 會以陣列的方式儲存在**堆(heap)**中,所以會更改最原本的字串 所以如果字串有頻繁的操作,才會使用string builder ```csharp! StringBuilder sb = new StringBuilder("i am Zeke."); sb.Append(" No, you are not Zeke."); // push() sb.Insert(1, "--"); sb.Remove(4, 2); sb.Replace(" ", "--"); Console.WriteLine(sb); ``` ## Array ### 基礎 ```csharp! // 聲明 int[] arr1 = {1, 2, 3}; int[] arr2 = new int[2] {1,2}; // 長度 Console.WriteLine(arr.Length); ``` ### 遍歷 ```csharp! int[] arr = {1, 2, 3, 4, 5}; foreach(int item in arr) { // 1 2 3 4 5,如同 arr.foreach((item) => {}) Console.WriteLine(item) } ``` ## enum 枚舉 在 class 內聲明枚舉 每個枚舉都有相對應的 index number,可自訂index,定義後面沒定義的會跟隨前面的index ```csharp! namespace HelloWorld { class Program { enum RoleType { Tank = 10, Warrior, // 11 Mage = 30, Assassin, // 31 Archer } static void Main(string[] args) { RoleType player1 = RoleType.Assassin; RoleType player2 = RoleType.Tank; } } } ``` ## struct 結構 簡易版的 class,需要實例化 `new` ```csharp! namespace HelloWorld { class Program { struct StudentInfo { public int id; public string name; public int age; private int adress; public void PrintStudentInfo() { Console.WriteLine($"名字:{name}"); } } static void Main(string[] args) { StudentInfo[] students = new StudentInfo[10]; students[0].name = "Zeke"; students[0].age = 24; students[0].id = 88965; students[0].PrintStudentInfo(); } } } ``` ## delegate 委託 可以引用擁有相同**params**和**返回值**的函數,這讓使用函數更加的簡便 ```csharp! delegate void IntMethodInvoker(int i); public static void Main(string[] args) { IntMethodInvoker invoker = null; invoker = Test; invoker(20); invoker = Test2; invoker(22); } private void Test(int i) {} private void Test2(int i) {} ``` 可以指向任一類別的靜態(static)函數,如同Object類別的ToString() ```csharp! delegate string GetString(); public static void Main(string[] args) { int a = 666; GetString invoker2 = a.ToString; Console.WriteLine(invoker2() + 222); //666222 } ``` 也可以指定成陣列型態的委託,讓訂閱和發佈的設計模式得以實現 ```csharp! delegate double MathDelegate(double i); public void Main() { MathDelegate[] operation = { MathOperator.Square, // 平方的函數 MathOperator.MutipllyByTwo // 相加的函數 }; Console.WriteLine(operation[0](5.5)); // 30.25 } ``` ### Action<> | Func<> 這Action 和 Func 本質上是簡短寫法的委託 #### 1. Action<> 返回值為 **void**,參數可以任意多個,也可以為無,但返回值必定 void ```csharp! public static void Main() { Action ac1 = AC1; Action<int, string> ac2 = AC2; } private static void AC1(){}; private static void AC2(int a, string b) {} ``` #### 2. Func<> 必須要有返回值,參數可以任一多個,且最後一個參數必定為返回值 ```csharp! public static void Main() { Func<string> f1 = FC1; Func<int, int, int> f2 = FC2; } private static string FC1() { return "Google"}; private static int FC2(int a, int b) { return a + b } ``` ## 匿名函數 | Lambda 匿名函數允許直接在函數體內制定另一函數,通常是式子簡短的普通計算為主 ```csharp! Func<int, int, int> plus = delegate (int a, int b) { int result = a + b return result; }; ``` ### Lambda 更簡寫的匿名函數,就是 JS的箭頭函數 ```csharp! Func<int, int, int> plus = (a, b) => { return a + b;}; Func<int, int> quare = a => a * a; ```