###### tags: `C#`
# **C#實作課程-Lesson 3**
# 方法(method)(續Lesson 2)
## out string 參數
```csharp=
static void Main(string[] args)
{
Console.WriteLine("請設定起始車資:");
int money = int.Parse(Console.ReadLine());
Console.WriteLine("是否為夜間加成時段(+30元):(Y/N)");
bool isNight = (Console.ReadLine() == "Y" ? true : false);
Console.WriteLine("是否使用後車行李箱(+10元):(Y/N)");
bool UseBox = (Console.ReadLine() == "Y" ? true : false);
//比照方法須填入out string 參數
var TotalMoney=CalTaxi(money,out string detailstr,isNight,UseBox);
Console.WriteLine($"車資一共為{TotalMoney}元~~");
Console.WriteLine(detailstr);
Console.ReadLine();
}
//建立方法時多設定一個out string參數,可用來回傳更多參數資訊
//(ex:此方法本來只能回傳一個int結果)
static int CalTaxi(int money, out string detail,bool isNight = false, bool UseBox = false)
{
if (isNight){ money += 30; }
if (UseBox) { money += 10; }
//使用out string參數,下面這行必須要寫出來
detail = $"車資為{money},夜間加成為{isNight},使用行李箱為{UseBox}";
return money;
}
```
※類似用法:TryParse
```csharp=
var w = "89.3";
if(int.TryParse(w,out int wval))//傳入w嘗試傳出wval
{
wval *= 2;
}
}
```
## ref 參數
```csharp=
static void Main(string[] args)
{
var y = "ABC";
MyMethod(y);
Console.WriteLine(y);//對照組;y值無改變
MyMethod2(ref y);//比照方法參數設定須加上ref
Console.WriteLine(y);//使用ref參數方法會改變原始輸入值
Console.ReadLine();
}
static void MyMethod(string x)
{
x = "DEF";
}
static void MyMethod2(ref string x)//參數宣告加上ref
{
x = "DEF";
}
```
# 例外處理(try catch)
## 例外處理原則
1.可以用程式方式檢查出的問題,不要使用例外處理(效能問題)
2.catch到例外後務必進行處理(ex: throw),**catch內不要空白不處理**
3.throw的內容可再進行包裝(避免原始碼和錯誤訊息直接被User看到)
## 語法
try
{
//執行的程式碼邏輯
}
catch
{
//如果try的區域發生錯誤,則執行catch裡面的內容
}
finally
{
//無論如何都會執行到的程式碼(通常用於**資源釋放**)
}
ex:
```csharp=
static void Main(string[] args)
{
try
{
var x = 1;
var result = x / 0;
}
catch (Exception e) //將例外狀況放在e變數
{
e.ToString();//,可將e轉成字串,後續可write to db....
throw ;//將例外狀況丟至上一層
}
}
```
偵錯結果如下

```csharp=
static void Main(string[] args)
{
try
{
var x = 1;
int result = x / 0;
}
catch (Exception e)
{
e.ToString();//write to db....
throw new Exception("System Error!!!");//可包裝錯誤訊息
}
}
```
偵錯結果如下

## Exception類別
●Exception
●SystemException
●ApplicationException
●NullReferenceException
●FileNotFoundException
●SerializationException
## 可針對不同Exception類別做不同處理
ex:
```csharp=
try
{
//執行的程式碼邏輯
}
catch(NullReferanceException ex)
{
// 針對NULLReferance的處理方式......
}
catch(Exception ex)
//其他例外的處理方式
finally
{
//無論如何都會執行到的程式碼(通常用於**資源釋放**)
}
```
# 類別(Class)與物件(Object)
## 類別(Class)
●規格、藍圖
●定義物件的抽象特徵,決定物件實體時的樣子
## 物件(Object)
●依照類別,具體實現而成的**執行個體(instance)**
●狀態可以在執行階段被改變
●實際配置記憶體
## 宣告類別
使用class關鍵字
```csharp=
public class Student
{
類別屬性
方法
欄位
}
```

## 建立物件
使用new關鍵字
```csharp=
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConsoleApp5.Models;//須寫出這行才能使用該資料夾的Class
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
Student a = new Student();//使用new建立新的物件
Student b = new Student();//a與b各為獨立物件
Student c = a;//c與a指向同樣物件
}
}
}
```

## 建立類別屬性
**快捷鍵prop:** 自動產生類別屬性格式
**快捷鍵///:** 自動產生註解(可以明確表示屬性用途)
get:可取得(預設public)
set:可設定(預設public)
```csharp=
public class Student
{
public Student()
{
this.ID = "A" + DateTime.Now.Millisecond;
}
/// <summary>
/// 編號
/// </summary>
public string ID { get; private set; }//private表示ID透過物件無法修改
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 電話
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 電子郵件
/// </summary>
public string Email { get; set; }
}
```
## 建構子(Constructor)
**快捷鍵ctor:** 自動產生建構子格式
1.建構子名稱會與class名稱相同
2.可讓產生物件時先具有建構子內的設定
※this關鍵字:類別內代稱物件用的字
```csharp=
public class Student
{
public Student()
{
this.ID = "A" + DateTime.Now.Millisecond;
}
/// <summary>
/// 編號
/// </summary>
public string ID { get; private set; }//private表示ID透過物件無法修改
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 電話
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 電子郵件
/// </summary>
public string Email { get; set; }
}
```
## get set舊式寫法
```csharp=
public class Student
{
private string _address;//先宣告私有變數
public string Address
{
get
{
return _address;//回傳變數內容
}
set
{
_address = value;//將value存至宣告變數內
}
}
//以上等同於↓
public string address { get; private set; }
//或可寫成↓
private string _address;
public string Address
{
get => _address;//簡化get的寫法
set
{
_address = value;
}
}
```
舊式寫法的用途(ex:須在set裡面判斷邏輯)
注意:
1.邏輯主要為簡單判斷,不應太複雜
2.邏輯寫在set裡面,不是在get裡面
```csharp=
public int age
{
get => _age;
set
{
if (value < 0 || value > 150)
{
throw new ArgumentOutOfRangeException($"{nameof(value)} .....");
}
_age = value;
}
}
```
## 自動屬性
C# 3 增加了自動實作屬性(automatically implemented properties),或簡稱「自動屬性」。這個新語法能夠讓我們在定義屬性時省去宣告私有欄位的麻煩,當類別裡面的屬性數量很多的時候,這個語法可以讓程式碼簡潔許多。請看底下的範例:
```csharp=
// C# 3:自動實作屬性(免寫私有欄位)。
public class Employee
{
public string ID { get; private set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
// 想像底下還有一堆屬性,而我們能夠省下多少私有欄位的宣告。
public Employee(string id) // 建構子
{
ID = id;
}
}
```
請注意屬性 ID 可讓外界讀取,但是只有類別本身才能修改其值。所謂的類別本身,當然包含類別的建構子和方法。可是,如果我們希望這個唯讀屬性只允許在建構子中設定一次初始值,以後就再也不能修改了——即使在類別的其他方法中也不能修改,這種情況要怎麼寫呢? C# 5 沒辦法做到——除非使用唯讀的私有欄位,但程式碼寫起來比較囉嗦。
## 唯讀自動屬性
到了 C# 6,終於在「不可改變性」(immutability)這方面做了改進,提供更好的寫法,也就是「唯讀自動屬性」(read-only automatically implemented properties)語法,像這樣:
```csharp=
// C# 6:唯讀的自動屬性。
public class Employee
{
public string ID { get; } // 沒有 setter,這是個唯讀自動屬性。
public Employee(string id)
{
ID = id; // 設定唯讀自動屬性的初始值。
}
private void ChangeID(int id)
{
ID = id; // 編譯失敗:ID 是唯讀屬性。
}
}
```
如您所見,此處有兩個重點:
1.屬性 ID 只有 getter,沒有 setter 了。它是個唯讀自動屬性。
2.由於 ID 是唯讀屬性,因此即使是類別自己也無法修改 ID 的值——建構子除外。
## 練習-建立客戶類別
```csharp=
//(建立Customer類別並寫在其中)
public class Customer
{
public Customer()
{
}
public string Name { get; set; }
public string Level { get; set; }
public Int64 Money { get; set; }
}
```
```csharp=
//(物件建立在主要執行Program中)
static void Main(string[] args)
{
Customer A = new Customer();
A.Name = "Amy";
A.Level = "normal";
A.Money = 100;
}
```
## 建構子內設定參數
產生物件時可先具有建構子內的設定
→輸入參數代表:物件建立時應該需實際給予參數內容
```csharp=
class Student
{
public Student(string name, string email)//物件建立需給予姓名和email內容
{
this.ID = "A" + DateTime.Now.Millisecond;
this.Email = email;//參數內容會存取在物件屬性變數內
this.Name = name;//參數內容會存取在物件屬性變數內
}
/// <summary>
/// 編號
/// </summary>
public string ID { get; private set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 電話
/// </summary>
public string Phone { get; set; }
/// <summary>
/// 電子郵件
/// </summary>
public string Email { get; set; }
}
}
```
↓類別建構子設定參數後,於主程式建立新物件時,需給予參數實際內容
```csharp=
static void Main(string[] args)
{
Student a = new Student("Amy", "123@gmail");//物件建立需給予姓名和email內容
Console.WriteLine(a.Name);//參數內容會存取在物件屬性變數內
Console.WriteLine(a.Email);//參數內容會存取在物件屬性變數內
Console.ReadLine();
```

## 類別內建立方法
ex:停車免費時數計算
1.建立類別Customer(同上面建立客戶類別)
```csharp=
//(建立Customer類別並寫在其中)
public class Customer
{
public string Name { get; set; }
public string Level { get; set; }
public Int64 Money { get; set; }
}
```
2.於類別內建立方法:計算免費停車時數
```csharp=
public class Customer
{
public string Name { get; set; }
public string Level { get; set; }
public Int64 Money { get; set; }
public int GetParkingTime()//建立方法(回傳int型別內容)
{
int times = 0;//預設可免費停車時數為0
Int64 Money = this.Money;//將物件消費的金額存入Money變數;
switch (this.Level)//判斷內容為:物件的Level屬性內容
{
case "VVIP":
times = (int) Money / 3000 * 2;//強制將Int64轉為int
if (times > 10) times = 10; break;
case "VIP":
times = (int) Money / 5000 * 2;
if (times > 6) times = 6; break;
case "normal":
times = (int) Money / 5000 * 2;
if (times > 2) times = 2; break;
}
return times;
}
```
3.於主程式內建立物件,並執行方法計算免費停車時數
```csharp=
class Program
{
static void Main(string[] args)
{
Customer A = new Customer();
A.Name = "Amy";
A.Level = "VVIP";
A.Money = 10000;
var Times=A.GetParkingTime();
Console.WriteLine($"{A.Name}顧客您好,可免費停車時數為{Times}!!!");
Console.ReadLine();
}
}
```
輸出結果如下↓

## 建立兩個類別,並讓兩個類別內的物件可以互動
ex:建立學生類別與課程類別,並挑出成績低於70分的課程
1.建立課程的類別
```csharp=
public class Course
{
public string Name { get; set; }
public int Score { get; set; }
}
```
2.建立學生的類別
```csharp=
public class Student2
{
public Student2(string no,string name)//學生編號&姓名
{
this.No = no;
this.Name = name;
this.MyCourse = new List<Course>();
//每次產生物件時,必須將List<T>初始化才能新增內容進去
}
public string No { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
public List<Course> MyCourse { get; set; }
//因為Course類別內有很多屬性,故使用List<T>型別儲存內容
}
```
3.於主程式建立學生物件與課程物件,將學生物件的課程新增內容進去,並挑出低於70分項目
```csharp=
class Program
{
static void Main(string[] args)
{
Student2 A = new Student2("A001","Amy");
Course CA = new Course();
CA.Name = "C#";
CA.Score = 95;
Course CB = new Course();
CB.Name = "db";
CB.Score = 65;
A.MyCourse.Add(CA);
A.MyCourse.Add(CB);
foreach(var item in A.MyCourse)
{
if(item.Score<70)
Console.WriteLine($"Name:{item.Name},Score:{item.Score}");
}
Console.ReadLine();
}
}
```
## 回家練習-網頁購物車
Q:建立學員、課程、購物車的類別並使其互動,能看出學員購買的課程有哪些,並計算加總購物金額
●自我試作↓
Student.cs
```csharp=
public class Student
{
public Student(string id,string name)
{
this.ID = id;
this.Name = name;
this.MyCourse = new List<Course>();
}
public string ID { get; set; }
public string Name { get; set; }
public List<Course> MyCourse { get; set; }
public double BuyingCar()
{
double money = 0;
foreach (var item in this.MyCourse)
money += item.Price;
if (money > 20000) { money *= 0.8; }
else if (money > 10000) { money *= 0.9; }
else money *= 0.8;
return money;
}
```
Course.cs
```csharp=
public class Course
{
public string CourseName { get; set; }
public int Price { get; set; }
public Course(string coursename,int price)
{
this.CourseName = coursename;
this.Price = price;
}
}
```
Program.cs
```csharp=
public class Program
{
static void Main(string[] args)
{
Student A = new Student("A001", "Amy");
Course C1 = new Course("C#",1000);
Course C2 = new Course("C++", 1800);
Course C3 = new Course("JAVA", 1500);
Course C4 = new Course("Python", 1200);
Course C5 = new Course("DataBase", 2500);
A.MyCourse.Add(C1);
A.MyCourse.Add(C2);
A.MyCourse.Add(C3);
A.MyCourse.Add(C4);
A.MyCourse.Add(C5);
double TotalMoney= A.BuyingCar();
Console.WriteLine($"總金額為{TotalMoney}元");
Console.ReadLine();
}
```
●參考答案↓(將購物車方法另外寫成一個類別)
Student.cs
```csharp=
public class Student
{
public Student(string id, string name)
{
this.ID = id;
this.Name = name;
this.MyCourse = new List<Course>();
}
public string ID { get; set; }
public string Name { get; set; }
public List<Course> MyCourse { get; set; }
}
```
Course.cs
```csharp=
public class Course
{
public string CourseName { get; set; }
public int Price { get; set; }
public Course(string coursename, int price)
{
this.CourseName = coursename;
this.Price = price;
}
}
```
BuyingCar.cs
```csharp=
public class BuyingCar
{
public double MyBuyingCar(Student x)
{
double money = 0;
foreach (var item in x.MyCourse)
money += item.Price;
if (money > 20000) { money *= 0.8; }
else if (money > 10000) { money *= 0.9; }
else money *= 0.8;
return money;
}
}
```
Program.cs
```csharp=
public class Program
{
static void Main(string[] args)
{
Student A = new Student("A001", "Amy");
Course C1 = new Course("C#", 1000);
Course C2 = new Course("C++", 1800);
Course C3 = new Course("JAVA", 1500);
Course C4 = new Course("Python", 1200);
Course C5 = new Course("DataBase", 2500);
BuyingCar B1 = new BuyingCar();
A.MyCourse.Add(C1);
A.MyCourse.Add(C2);
A.MyCourse.Add(C3);
A.MyCourse.Add(C4);
A.MyCourse.Add(C5);
double TotalMoney = B1.MyBuyingCar(A);
Console.WriteLine($"總金額為{TotalMoney}元");
Console.ReadLine();
}
}
```