ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

C# - カプセル化・アクセシビリティ・継承・アセンブリ

初めに

 C#オブジェクト指向型のプログラミング言語です。本記事では、private や public などアクセス修飾子に関わるカプセル化と呼ばれる概念について、まとめます。また、継承やアセンブリについても簡単に説明しています。


オブジェクト指向型について

 C#言語はオブジェクト指向型のプログラミング言語です。オブジェクト指向とは、

オブジェクト(モノ)を組み立てるようにプログラムを書き、モノとモノの関係性を定義することでシステムを作り上げようとするシステム構成の考え方

のことです。

fineworks-fine.hatenablog.com

カプセル化

 オブジェクト指向では "カプセル化" と呼ばれる考え方に基づいてプログラミングを行います。

 カプセル化とは、

オブジェクトの情報を隠蔽することによって、不整合を引き起こすような操作をできなくさせる仕組み

です。
 オブジェクトは中身(内部実装)がどうなっているのかを隠蔽し、 可能な操作(関数、メソッド)と属性(プロパティ)のみを公開することで、外部からの直接的なアクセスを防ぎ、バグの発生を抑制できます。

アクセシビリティ・アクセス修飾子

 変数や関数には、アクセシビリティ(Accessibility: アクセスできる度合い)があります。private や public などアクセス修飾子をつけることでアクセシビリティを制御することが出来ます。

アクセス修飾子 説明
public どこからでもアクセス可能
protected internal 同一プロジェクト内のクラス内部、または、派生クラスの内部からのみアクセス可能
protected クラス内部と、派生クラスの内部からのみアクセス可能
internal 同一プロジェクト内のクラスからのみアクセス可能
private protected 同一プロジェクト内のクラス内部、かつ、派生クラスの内部からのみアクセス可能
private クラス内部からのみアクセス可能

※アクセス修飾子を省略した場合は、private になります。
※派生については下記の継承で、アセンブリについてはプロジェクトの分割で説明します。

アクセス修飾子の付け方

 アクセス修飾子は変数や関数の定義の前につけます。

//変数の場合
public int number = 1;

//関数の場合
private void Method()
{
      Debug.Log("この関数はprivateです");
}

継承・派生

継承(inheritance)とは、

あるクラスから性質を受け継いだ新しいクラスを作ること

です。派生(derivation)とも呼ばれます。

 継承は集合の包含関係があるものを表現するときに使います。

 「動物」と「犬」という2つのクラスを例に用いて説明します。この2つのクラスについて、次の関係が成り立ちます。

  • 「犬」⊂「動物」:「犬」は「動物」に含まれる
  • 「動物」⊄「犬」:「動物」は「犬」に含まれない

 「犬」は「動物」に含まれるので、「動物」の属性を備えています。

継承関係

 2つのクラス A, B において、 B ⊂ A (A が B を含む)が成り立つ関係にあるとき、この関係を継承関係と呼び、B は A を継承する(B は A から派生する)といいます。また、このとき、A を基底クラス(base class、super class)といい、B を派生クラス(derived class、sub class)とよびます。

クラスの継承の仕方

 次のように記述することで、クラスの継承をすることができます。

//クラスの継承の仕方
// sub には派生クラス名を, base には基底クラス名を記述
class sub : base
{
      //派生クラスの定義
} 

(例)

class Animal
{
    private string name;  //名前
    protected int age;  //年齢
}

class Dog : Animal
{
    public string breed;  //品種
}

 派生クラスは基底クラスとして扱えますが、基底クラスは派生クラスとして扱えません。つまり、派生クラスのインスタンスを基底クラスの変数に代入することはできますが、基底クラスのインスタンスを派生クラスに代入することはできません。

(例)

//Animalは基底クラス
Animal a1 = new Animal();
a1.name = "太郎";
a1.age = 8;

//Dogは派生クラス
Dog d1 = new Dog();
d1.name = "はち";  //派生クラスは基底クラスの変数を利用できる
d1.age = 6;
d1.breed = "shiba";


//Dog は Animal の派生クラスなのでAnimal として扱える
Animal a2 = d1;

(できない例)

//これはエラーになります。
Dog d2 = a1;

 派生クラスである「犬」は「動物」なので、基底クラスの「動物」としても扱えますが、「動物」であっても「犬」とは限らないので、基底クラスを派生クラスとして扱うことはできません。

object 型

 object 型は、すべてのクラスとすべての値型・参照型の基底クラスです。

 基底クラスを指定せずに作成した型はすべて object 型を継承することになります。

 object 型で定義されている関数には、以下のものがあります。

返り値 関数 説明
bool Equal 引数内のオブジェクトが等しいかどうか
int GetHashCode オブジェクトに関連付けられたハッシュコードを返す
Type GetType オブジェクトのタイプを返す
string ToString オブジェクトを表す文字列を返す

learn.microsoft.com

protected

 protected はクラスとそのクラスを継承する派生クラス内からアクセス可能です。

(例)

class Animal
{
    public string name;  //名前
    protected int age;  //年齢
    private string habitat; //生息地
}

class Drived : Animal
{
    void Test()
    {
         name = "Jiro";  //ok
         age = 10:  //ok(protectedは派生クラスからアクセスできる
        habitat = "Japan";  //エラー(privateは派生クラスからアクセスできない)
    }
}
sealed(継承禁止)

 クラスを定義するときに sealed をつけることで、継承を禁止することができます。

//継承禁止のクラスの定義
sealed class Base()
{
    //基底クラス
}

アセンブリ

アセンブリとは

 アセンブリ(部品、組み立て部品)とは、

Microsoft .NET Frameworkの環境における、アプリケーションなどの管理単位となるコンパイル済みのコード群のこと

です。アセンブリは exe や dll ファイル として実行されます。

 基本的に C# では、プロジェクト内の複数のソースコードコンパイル結果を1つのファイルにまとめて出力されます。その出力されたファイルがアセンブリになります。

プロジェクトを分割する場合

 プロジェクトを分割しない限り internal のようなアセンブリ間のアクセシビリティを考える必要はありません。

 しかし、次のようなプロジェクトを分割したい場合がでてきます。

  • 異なる動作環境で動かしたい(Android, iOS, Windows など)
  • 特定の部分だけ切り出したい(テスト用に特定の部分だけ抜き出して実行したい)
  • 開発者用と本体を変えたい

 このように、プロジェクトを分割する必要がでた場合はそれぞれのプロジェクト間での依存関係を考える必要がでてきます。

Unity の場合

 Assembly Definition(アセンブリ定義)という機能があります。これによりC#アセンブリ(ビルドファイル)を分割することができます。
docs.unity3d.com

参考

ufcpp.net

最後に

 public、protected、private の違いと継承だけでも使えるようにしたいものです。