クラスの概要

参照型

class として定義された型は、"参照型" です。 実行時に、参照型の変数を宣言すると、new 演算子を使用してクラスのインスタンスを明示的に作成するまで、変数には値 null が格納されています。または、次の例に示すように、別の場所で作成された可能性がある、互換性のある型のオブジェクトを代入することもできます。

//Declaring an object of type MyClass.
MyClass mc = new MyClass();

//Declaring another object of the same type, assigning it the value of the first object.
MyClass mc2 = mc;

オブジェクトが作成されると、その特定のオブジェクトに対してマネージド ヒープ上で十分なメモリが割り当てられ、変数にはそのオブジェクトの場所への参照のみが格納されます。 オブジェクトによって使われるメモリは、CLR の自動メモリ管理機能 ("ガベージ コレクション" と呼ばれます) によって再利用されます。 ガベージ コレクションの詳細については、「自動メモリ管理とガベージ コレクション」を参照してください。

クラスの宣言

クラスは、次の例に示すように、class キーワードと、その後に続ける一意の識別子を使用して宣言します。

//[access modifier] - [class] - [identifier]
public class Customer
{
   // Fields, properties, methods and events go here...
}

class キーワードの前には、省略可能なアクセス修飾子が付きます。 この例では、public が使用されているため、誰でもこのクラスのインスタンスを作成できます。 class キーワードの後にクラスの名前を記述します。 クラスの名前を、有効な C# の識別子名にする必要があります。 定義の残りの部分がクラス本体で、そこで動作とデータを定義します。 クラスのフィールド、プロパティ、メソッド、およびイベントはクラス メンバーと総称されます。

オブジェクトの作成

クラスとオブジェクトは、同義的に使われることがありますが、これらは異なるものです。 クラスはオブジェクトの型を定義しますが、オブジェクト自体ではありません。 オブジェクトは、クラスに基づく具体的なエンティティであり、クラスのインスタンスと呼ばれることもあります。

オブジェクトを作成するには、new キーワードの後にクラス名を指定します。

Customer object1 = new Customer();

クラスのインスタンスを作成すると、そのオブジェクトへの参照が返されます。 前の例の object1 は、Customer に基づくオブジェクトへの参照です。 この参照は、新しいオブジェクトを参照しますが、オブジェクト データ自体を含みません。 実際、オブジェクト参照は、オブジェクトを作成しなくても作成できます。

Customer object2;

オブジェクトを参照しないオブジェクト参照を作成するのはお勧めしません。実行時にこのような参照を通じてオブジェクトへのアクセスを試みると失敗するからです。 新しいオブジェクトを作成するか、既存のオブジェクトを割り当てると、参照でオブジェクトを参照できるようになります。次に例を示します。

Customer object3 = new Customer();
Customer object4 = object3;

上のコードでは、同じオブジェクトを参照する 2 つのオブジェクト参照が作成されます。 そのため、object3 を通じて行われたオブジェクトの変更は、後で object4 を使用するときに反映されます。 これは、クラスに基づくオブジェクトが参照によって参照されるからです。このためクラスは参照型と呼ばれています。

コンストラクターと初期化

前のセクションでは、クラスの型を宣言し、その型のインスタンスを作成する構文を紹介しました。 型のインスタンスを作成するときには、そのフィールドやプロパティが有用な値に初期化されていることを確認する必要があります。 値を初期化するには、いくつかの方法があります。

  • 既定値を受け入れる
  • フィールド初期化子
  • コンストラクターのパラメーター
  • オブジェクト初期化子

すべての .NET 型には既定値があります。 通常、その値は数値型の場合は 0、すべての参照型の場合は null です。 アプリに適している場合は、その既定値を利用することができます。

.NET の既定値が適切でない場合は、"フィールド初期化子" を使って初期値を設定できます。

public class Container
{
    // Initialize capacity field to a default value of 10:
    private int _capacity = 10;
}

呼び出し元に初期値の指定を要求するには、初期値の設定を担当する "コンストラクター" を定義します。

public class Container
{
    private int _capacity;

    public Container(int capacity) => _capacity = capacity;
}

C# 12 以降では、"プライマリ コンストラクター" をクラス宣言の一部として定義できます。

public class Container(int capacity)
{
    private int _capacity = capacity;
}

クラス名にパラメーターを追加することで、"プライマリ コンストラクター" が定義されます。 これらのパラメーターは、そのメンバーを含むクラス本文で使用できます。 これらを使って、フィールドまたはその他の必要な場所を初期化できます。

また、required 修飾子をプロパティに使い、呼び出し元が "オブジェクト初期化子" を使ってプロパティの初期値を設定することを許可することもできます。

public class Person
{
    public required string LastName { get; set; }
    public required string FirstName { get; set; }
}

required キーワードを追加すると、new 式の一部としてこれらのプロパティを設定することが呼び出し元に義務付けられます。

var p1 = new Person(); // Error! Required properties not set
var p2 = new Person() { FirstName = "Grace", LastName = "Hopper" };

クラスの継承

クラスは、オブジェクト指向プログラミングの基本的な特性である "継承" を完全にサポートします。 クラスを作成すると、sealedとして定義されていないその他のクラスから継承することができます。 他のクラスは、クラスから継承し、クラスの仮想メソッドをオーバーライドできます。 さらに、1 つまたは複数のインターフェイスを実装できます。

継承は、派生を使用して行われます。派生とは、データの動作の継承元である基底クラスを使用してクラスを宣言することを意味します。 基底クラスは、派生クラス名の後に、コロンと基底クラス名を追加して指定します。次に例を示します。

public class Manager : Employee
{
    // Employee fields, properties, methods and events are inherited
    // New Manager fields, properties, methods and events go here...
}

クラスの宣言に基底クラスが含まれている場合、基底クラスのすべてのメンバー (コンストラクター以外) が継承されます。 詳細については、「継承」を参照してください。

C# のクラスは 1 つの基底クラスから直接継承することしかできません。 ただし、基底クラス自体が別のクラスを継承している場合があるため、1 つのクラスに複数の基底クラスが間接的に継承されることもあります。 さらに、クラスは 1 つまたは複数のインターフェイスを直接実装できます。 詳細については、「インターフェイス」を参照してください。

クラスは abstract として宣言できます。 抽象クラスには、シグネチャ定義が存在し、実装は存在しない抽象メソッドが含まれています。 抽象クラスはインスタンス化できません。 抽象クラスを使用するには、抽象メソッドを実装する派生クラスを介する必要があります。 これとは対照的に、シール クラスは、他のクラスに派生させることはできません。 詳細については、「抽象クラスとシール クラス、およびクラス メンバー」を参照してください。

クラス定義は、別々のソース ファイルに分割できます。 詳細については、「部分クラスと部分メソッド」を参照してください。

C# 言語仕様

詳細については、「C# 言語の仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。