[C#] 継承/object型/ポリモーフィズム/インターフェース/例外処理について

クラスの継承
---

```C#:ClassSample
using System;
using System.Collections.Generic;
using System.Linq;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            var employee = new Employee
            {
                Number = 368,
                FirstName = "ともや",
                LastName = "鈴木",
                HireDate = new DateTime(2016, 10, 3)
            };
            Console.WriteLine("従業員番号{0}の{1}は、{2}年に入社しました",
                employee.Number, employee.FullName, employee.HireDate.Year);
        }   
    }

    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName
        {
            get { return LastName + FirstName; }
        }
        public string Email { get; set; }
    }

    //従業員クラス
    class Employee : Person    //Personクラスを継承
    {
        //従業員番号
        public int Number { get; set; }
        //入社年月日
        public DateTime HireDate { get; set; }
    }

    //顧客クラス
    class Customer : Person
    {
        //顧客ID
        public string Id { get; set; }
        //顧客ランク
        public int Rank { get; set; }
        //クレジットカード番号
        public string CreditCardNumber { get; set; }
    }
}
```
**継承におけるメソッド**

```C#:ClassSample
using System;
using System.Collections.Generic;
using System.Linq;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            var employee = new Employee
            {
                Number = 368,
                FirstName = "ともや",
                LastName = "鈴木",
                Email = "tomotomo@example.com",
                HireDate = new DateTime(2016, 10, 3)
            };
            Console.WriteLine("従業員番号{0}の{1}は、{2}年に入社しました",
                employee.Number, employee.FullName, employee.HireDate.Year);

            //メソッドの呼び出し
            var person = new Person
            {
                FirstName = "ゆか",
                LastName = "佐々木",
                Email = "sasasa@example.com"
            };
            person.Print();
            employee.Print();
        }   
    }

    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName
        {
            get { return LastName + FirstName; }
        }
        public string Email { get; set; }

        public void Print() //メソッドを追加
        {
            Console.WriteLine($"名前: {FullName} ({Email})");
        }
    }

    class Employee : Person
    {
        public int Number { get; set; }
        public DateTime HireDate { get; set; }
    }

    class Customer : Person
    {
        public string Id { get; set; }
        public int Rank { get; set; }
        public string CreditCardNumber { get; set; }
    }
}
```

**メソッドのオーバーライド(上書き)**

```C#:ClassSample
using System;
using System.Collections.Generic;
using System.Linq;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            var employee = new Employee
            {
                Number = 368,
                FirstName = "ともや",
                LastName = "鈴木",
                Email = "tomotomo@example.com",
                HireDate = new DateTime(2016, 10, 3)
            };
            employee.Print();   //オーバライドしたEmployeeクラスのPrintメソッドを呼び出す

            var person = new Person
            {
                FirstName = "ゆか",
                LastName = "佐々木",
                Email = "sasasa@example.com"
            };
            person.Print(); //PersonクラスのPrintメソッドを呼び出す
        }   
    }

    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName
        {
            get { return LastName + FirstName; }
        }
        public string Email { get; set; }

        public virtual void Print() //virtualキーワードをつけるとサブクラスでオーバライドできる
        {
            Console.WriteLine($"名前: {FullName} ({Email})");
        }
    }

    class Employee : Person
    {
        public int Number { get; set; }
        public DateTime HireDate { get; set; }

        // overrideキーワードでメソッドを上書きできる
        public override void Print()
        {
            Console.WriteLine($"{Number}:{FullName}({Email}) {HireDate.Year}年入社");
        }
    }

    class Customer : Person
    {
        public string Id { get; set; }
        public int Rank { get; set; }
        public string CreditCardNumber { get; set; }
    }
}
```
**object型**
**ToStringメソッドをオーバーライドする**

```C#:ClassSample
using System;
using System.Collections.Generic;
using System.Linq;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            //呼び出し
            var employee = new Employee()
            {
                Number = 368,
                FirstName = "ともや",
                LastName = "鈴木",
                Email = "tomotomo@example.com",
                HireDate = new DateTime(2016, 10, 3)
            };
            var s = employee.ToString();    //オーバーライドしたToStringメソッドを呼び出す
            Console.WriteLine(s);

            var person = new Person
            {
                FirstName = "ゆか",
                LastName = "佐々木",
                Email = "sasasa@example.com"
            };
            person.Print();
        }   
    }

    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName
        {
            get { return LastName + FirstName; }
        }
        public string Email { get; set; }

        public virtual void Print()
        {
            Console.WriteLine($"名前: {FullName} ({Email})");
        }
    }

    class Employee : Person
    {
        public int Number { get; set; }
        public DateTime HireDate { get; set; }

        public override string ToString()   //ToStringメソッドをオーバーライド
        {
            var s = $"{Number} {FullName} " + $"{HireDate.Year}年{HireDate.Month}月{HireDate.Day}日入社";
            return s;
        }
    }

    class Customer : Person
    {
        public string Id { get; set; }
        public int Rank { get; set; }
        public string CreditCardNumber { get; set; }
    }
}
```
ポリモーフィズム
---
**種類の異なるクラスを同一視する**

```C#:ClassSample
using System;
using System.Collections.Generic;
using System.Linq;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            VirtualPet pet1 = new FoodiePet("たべお");
            VirtualPet pet2 = new CheerfulPet("ゲンキ");
            VirtualPet pet3 = new SleepyPet("ねむお");
            var pets = new List<VirtualPet>();
            pets.Add(pet1); //3つのオブジェクトをvirtualPet型のリストに格納
            pets.Add(pet2); //3つのオブジェクトをvirtualPet型のリストに格納
            pets.Add(pet3); //3つのオブジェクトをvirtualPet型のリストに格納

            foreach (var pet in pets)
            {
                pet.Eat();
                pet.Play();
                Console.WriteLine($"{pet.Name} 機嫌:{pet.Mood} エネルギー:{pet.Energy}");
            }
        }   
    }
    class VirtualPet
    {
        public string Name { get; private set; }
        public int Mood { get; set; }
        public int Energy { get; set; }

        //コンストラクター
        public VirtualPet(string name)
        {
            Name = name;
            Mood = 5;
            Energy = 100;
        }

        public virtual void Eat()   //virtualキーワードを使っている
        {

        }
        public virtual void Play()
        {

        }
        public virtual void Sleep()
        {

        }
    }

    class FoodiePet : VirtualPet
    {
        public FoodiePet(string name) : base(name)  //baseキーワードで継承元のコンストラクターを呼び出す
        {

        }

        public override void Eat()  //overrideを使って上書き定義
        {
            Mood += 3;
            Energy += 5;
            Console.WriteLine("FoodiePet.Eatメソッドが実行されました");
        }

        public override void Play() //overrideを使って上書き定義
        {
            Mood -= 1;
            Energy -= 10;
            Console.WriteLine("FoodiePet.Playメソッドが実行されました");
        }

        public override void Sleep()    //overrideを使って上書き定義
        {
            Mood -= 1;
            Energy += 2;
            Console.WriteLine("FoodiePet.Sleepメソッドが実行されました");
        }
    }

    class CheerfulPet : VirtualPet
    {
        public CheerfulPet(string name) : base(name)
        {

        }
        public override void Eat()
        {
            Mood += 0;  //値は変化しない
            Energy += 5;
            Console.WriteLine("CheerfulPet.Eatメソッドが実行されました");
        }
        public override void Play()
        {
            Mood += 3;
            Energy -= 10;
            Console.WriteLine("CheerfulPet.Playメソッドが実行されました");
        }

        public override void Sleep()
        {
            Mood -= 1;
            Energy += 2;
            Console.WriteLine("CheerfulPet.Sleepメソッドが実行されました");
        }
    }

    class SleepyPet : VirtualPet
    {
        public SleepyPet(string name) : base(name)
        {

        }
        public override void Eat()
        {
            Mood -= 1;
            Energy += 5;
            Console.WriteLine("SleepyPet.Eatメソッドが実行されました");
        }
        public override void Play()
        {
            Mood -= 1;
            Energy -= 10;
            Console.WriteLine("SleepyPet.Playメソッドが実行されました");
        }

        public override void Sleep()
        {
            Mood += 2;
            Energy += 2;
            Console.WriteLine("SleepyPet.Sleepメソッドが実行されました");
        }
    }
}
```
抽象クラス
---
**abstractの付いたクラスを抽象クラスという**
**・これを使用してvirtualPetクラスのインスタンスを生成できなくすることができる**
abstract class VirtualPet
{
・・・・・
}

**抽象メソッド**
・メソッドを抽象メソッドとした場合は、サブクラスでは必ず、overrideキーワードでメソッドを上書きする必要がある

```C#:ClassSample
abstract class VirtualPet
    {
        public string Name { get; private set; }
        public int Mood { get; set; }
        public int Energy { get; set; }

        //コンストラクター
        public VirtualPet(string name)
        {
            Name = name;
            Mood = 5;
            Energy = 100;
        }

        public abstract void Eat();     //abstractキーワードで抽象メソッドにする
        public abstract void Play();    //abstractキーワードで抽象メソッドにする
        public abstract void Sleep();   //abstractキーワードで抽象メソッドにする

    }
```
インターフェース
---

```C#:ClassSample
using System;
using System.Collections.Generic;
using System.Linq;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            var pets = new List<IVirtualPet>();
            var pet1 = new FoodiePet("たべお");
            var pet2 = new CheerfulPet("ゲンキ");
            var pet3 = new SleepyPet("ねむお");
            pets.Add(pet1);
            pets.Add(pet2);
            pets.Add(pet3);

            foreach (var pet in pets)
            {
                pet.Eat();
                pet.Play();
                Console.WriteLine($"{pet.Name} 機嫌:{pet.Mood} エネルギー:{pet.Energy}");
            }
        }   
    }

    interface IVirtualPet   //interfaceキーワードでインターフェースを定義
    {
        string Name { get; }
        int Mood { get; set; }
        int Energy { get; set; }
        void Eat();
        void Play();
        void Sleep();
    }



    class FoodiePet : IVirtualPet
    {
        public string Name { get; private set; }
        public int Mood { get; set; }
        public int Energy { get; set; }

        public FoodiePet(string name)
        {
            Name = name;
            Mood = 5;
            Energy = 100;
        }
        public void Eat()   //インターフェースを実装する場合はoverrideは不要
        {
            Mood += 3;
            Energy += 5;
            Console.WriteLine("FoodiePet.Eatメソッドが実行されました");
        }
        public void Play()  //インターフェースを実装する場合はoverrideは不要
        {
            Mood -= 1;
            Energy -= 10;
            Console.WriteLine("FoodiePet.Playメソッドが実行されました");
        }

        public void Sleep() //インターフェースを実装する場合はoverrideは不要
        {
            Mood -= 1;
            Energy += 2;
            Console.WriteLine("FoodiePet.Sleepメソッドが実行されました");
        }
    }

    class CheerfulPet : IVirtualPet
    {
        public string Name { get; private set; }
        public int Mood { get; set; }
        public int Energy { get; set; }

        public CheerfulPet(string name)
        {
            Name = name;
            Mood = 5;
            Energy = 100;
        }
        public void Eat()   //インターフェースを実装する場合はoverrideは不要
        {
            Mood += 0;
            Energy += 5;
            Console.WriteLine("CheerfulPet.Eatメソッドが実行されました");
        }
        public void Play()  //インターフェースを実装する場合はoverrideは不要
        {
            Mood += 3;
            Energy -= 10;
            Console.WriteLine("CheerfulPet.Playメソッドが実行されました");
        }

        public void Sleep() //インターフェースを実装する場合はoverrideは不要
        {
            Mood -= 1;
            Energy += 2;
            Console.WriteLine("CheerfulPet.Sleepメソッドが実行されました");
        }
    }

    class SleepyPet : IVirtualPet
    {
        public string Name { get; private set; }
        public int Mood { get; set; }
        public int Energy { get; set; }

        public SleepyPet(string name)
        {
            Name = name;
            Mood = 5;
            Energy = 100;
        }
        public void Eat()   //インターフェースを実装する場合はoverrideは不要
        {
            Mood -= 1;
            Energy += 5;
            Console.WriteLine("SleepyPet.Eatメソッドが実行されました");
        }
        public void Play()  //インターフェースを実装する場合はoverrideは不要
        {
            Mood -= 1;
            Energy -= 10;
            Console.WriteLine("SleepyPet.Playメソッドが実行されました");
        }

        public void Sleep() //インターフェースを実装する場合はoverrideは不要
        {
            Mood += 2;
            Energy += 2;
            Console.WriteLine("SleepyPet.Sleepメソッドが実行されました");
        }
    }
}
```
例外処理
---
例外をキャッチする

```C#:ClassSample
using System;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            try
            {
                var total = 1000;
                var line = Console.ReadLine();
                var count = int.Parse(line);
                var ans = total / count;
                Console.WriteLine(ans);
                Console.WriteLine("正常終了");
            }
            catch
            {
                Console.WriteLine("入力した値が正しくありません");
            }
        }   
    }
}
```

**例外の種類を指定してキャッチする**

```C#:ClassSample
using System;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            try
            {
                var total = 1000;
                var line = Console.ReadLine();
                var count = int.Parse(line);
                var ans = total / count;
                Console.WriteLine(ans);
                Console.WriteLine("正常終了");
            }
            catch (System.DivideByZeroException)
            {
                Console.WriteLine("ゼロは入力できません");
            }
            catch (System.FormatException)
            {
                Console.WriteLine("数値を入力してください");
            }
            catch (System.Exception)
            {
                Console.WriteLine("予期しないエラーが発生しました");   //全てキャッチできるが最後に書かないと他のエラーがキャッチできなくなるので注意が必要
            }

        }   
    }
}
```
**例外オブジェクトの参照**

```C#:ClassSample
using System;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            try
            {
                Book book = null;
                var title = book.Title;
                Console.WriteLine(title);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Type: {ex.GetType().Name}");
                Console.WriteLine($"Message: {ex.Message}");
                Console.WriteLine($"TargetSite: {ex.TargetSite}");
                Console.WriteLine($"StackTrace: {ex.StackTrace}");
            }
        }   
    }

    class Book
    {
        public string Title { get; set; }
        public string Auther { get; set; }
        public int Pages { get; set; }
        public int Rating { get; set; }

        public Book(string title, string auther, int pages, int rating)
        {
            Title = title;
            Auther = auther;
            Pages = pages;
            Rating = rating;
        }
    }
}
```
**例外を発生させる**
スローした例外をキャッチする

```C#:ClassSample
using System;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            try
            {
                var bc = new BmiCalculator();
                var bmi = bc.GetBmi(1.57, 49.5);
                Console.WriteLine(bmi);
            }
            catch (ArgumentException ex)  //ArgumentExceptionだけをキャッチする
            {
                Console.WriteLine(ex.Message);
            }
        }   
    }

    class BmiCalculator
    {
        public double GetBmi(double height, double weight)
        {
            if (height < 60.0 || 250 < height)
            {
                throw new ArgumentException("heightの指定に誤りがあります"); //例外をスローする
            }
            if (weight < 10.0 || 200.0 < weight)
            {
                throw new ArgumentException("weightの指定に誤りがあります"); //例外をスローする
            }
            var metersTall = height / 100.0;
            var bmi = weight / (metersTall * metersTall);
            return bmi;
        }
    }
}
```
**try-finallyによる後処理**

```C#:ClassSample
using System;
using System.IO;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            try
            {
                ReadSample();
            }
            catch
            {
                Console.WriteLine("ReadSampleでエラーが発生");
            }
        }

        private static void ReadSample()
        {
            var file = new StreamReader("test.txt");
            try
            {
                while (file.EndOfStream == false)
                {
                    var line = file.ReadLine();
                    Console.WriteLine(line);
                }
            }
            finally
            {
                file.Dispose();
            }
        }
    }
}
```
**usingによる後処理**
using文はIDisposableインターフェースを実装しているクラスのインスタンスを生成するときだけ使える

```C#:ClassSample
using System;
using System.IO;

namespace ClassSample
{
    class Program
    {
        static void Main()
        {
            try
            {
                ReadSample();
            }
            catch
            {
                Console.WriteLine("ReadSampleでエラーが発生");
            }
        }

        private static void ReadSample()
        {
            using (var file = new StreamReader("test.txt"))
            {
                while (file.EndOfStream == false)
                {
                    var line = file.ReadLine();
                    Console.WriteLine(line);
                }
            }   //Disposeメソッドは書かれていないが、最後にfile.Disaposeが呼ばれる
        }
    }
}
```