---
# System prepended metadata

title: '**C#實作課程-Lesson 3**'
tags: [C#]

---

###### 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 ;//將例外狀況丟至上一層
            }
        } 
```
偵錯結果如下
![](https://i.imgur.com/xFY8ISC.png)
```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!!!");//可包裝錯誤訊息
            }
        } 
```
偵錯結果如下
![](https://i.imgur.com/XyIEca3.png)


##    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
    {
    類別屬性
    方法
    欄位
    }
    
```
![](https://i.imgur.com/bCtSMu0.png)

##    建立物件
使用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指向同樣物件
        } 


    }
}
```
![](https://i.imgur.com/4x5mxJP.png)

##    建立類別屬性
**快捷鍵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();
```
![](https://i.imgur.com/n8LLZZP.png)
##    類別內建立方法
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();
        }

    }
```
輸出結果如下↓
![](https://i.imgur.com/9B6nJV6.png)
##    建立兩個類別，並讓兩個類別內的物件可以互動
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();
        }
    }
```