###### 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>)
```
## 變數

### 強轉換
```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;
```