ヒント
ソフトウェアの開発は初めてですか? 最初に、 作業の開始 に関するチュートリアルから始めます。 動作と状態を持つオブジェクトをモデル化する必要がある場合は、クラスが発生します。
別の言語で経験がありますか? C# クラスは、Java または C++ のクラスに似ています。 C# 固有のパターンの オブジェクト初期化子 セクションをスキミングし、データに重点を置いた代替手段の レコード を参照してください。
クラスは、オブジェクトのブループリントを定義する参照型です。 クラス型の変数を作成すると、その変数はマネージド ヒープ上のオブジェクトへの 参照 を保持します。 変数はオブジェクト データ自体を保持しません。 クラス変数を別の変数に割り当てると参照がコピーされるため、両方の変数が同じオブジェクトを指します。 クラスは、C# でカスタム型を定義する最も一般的な方法です。 参照間で複雑な動作、継承、または共有 ID が必要な場合に使用します。
クラスを使用するタイミング
次の場合にクラスを使用します。
- この型は複雑な動作を持っているか、変更可能な状態を管理します。
- 派生特殊化を使用して基底クラスを作成したり、既存のクラスを拡張する派生型を作成したりするには、継承が必要です。
- インスタンスは、等しい値を保持するオブジェクトではなく、共有 ID を表します。 同じオブジェクトへの 2 つの参照は同期された状態を維持する必要があります。
- 型が大きいか、保存期間が長い場合は、ヒープ割り当てと参照セマンティクスの利点を享受できます。
クラスを宣言します
class キーワードの後に型名が続くクラスを定義します。 オプションの アクセス修飾子 は、可視性を制御します。 既定値は、internal です。 他のアセンブリからの呼び出し元が型を使用できるようにするには、 public を指定します。
public class Customer
{
public string Name { get; set; }
public Customer(string name) => Name = name;
}
クラス本体には、フィールド、プロパティ、メソッド、およびイベントが含まれており、まとめて クラス メンバーと呼ばれます。 名前は有効な C# 識別子名である必要があります。
オブジェクトの作成
クラスは型を定義しますが、オブジェクト自体ではありません。
キーワードを使用してオブジェクト (クラスのnew) を作成します。
var customer = new Customer("Allison");
Console.WriteLine(customer.Name); // Allison
変数 customer は、オブジェクト自体ではなく、オブジェクトへの参照を保持します。 同じオブジェクトに複数の変数を割り当てることができます。 一方の参照を介した変更は、もう一方の参照を通じて表示されます。
var c1 = new Customer("Grace");
var c2 = c1; // both variables reference the same object
c2.Name = "Hopper";
Console.WriteLine(c1.Name); // Hopper — c1 sees the change made through c2
この参照共有動作は、クラスと構造体の 1 つの違 いです。 構造体を使用すると、割り当てによってデータがコピーされます。 さらに重要なのは、クラスが 継承をサポートすることです。 派生型が再利用され、基底クラスからの動作を特殊化する階層を構築できます。 構造体は継承階層に参加できません。 区別の詳細については、「値の 型と参照型」を参照してください。
コンストラクターと初期化
インスタンスを作成するときは、そのフィールドとプロパティを有用な値に初期化する必要があります。 C# には、フィールド初期化子、コンストラクター パラメーター、プライマリ コンストラクター、および必須プロパティといういくつかの方法があります。
フィールド初期化子は、フィールド 宣言で既定値を直接設定します。
public class Container
{
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;
}
プライマリ コンストラクターとフィールド初期化子は連携できます。フィールド初期化子 _capacity = capacity は、プライマリ コンストラクター パラメーターを値として使用します。 このパターンを使用すると、1 つの簡潔な宣言でフィールド内のコンストラクター引数をキャプチャできます。
必要なプロパティ は、呼び出し元がオブジェクト初期化子を使用して特定のプロパティを設定することを強制します。
public class Person
{
public required string FirstName { get; set; }
public required string LastName { get; set; }
}
// var missing = new Person(); // Error: required properties not set
var person = new Person { FirstName = "Grace", LastName = "Hopper" };
Console.WriteLine($"{person.FirstName} {person.LastName}"); // Grace Hopper
パラメーターの検証やコンストラクターのチェーンなど、コンストラクター パターンの詳細については、「 コンストラクター」を参照してください。
静的クラス
static クラスはインスタンス化できません。静的メンバーのみを含みます。 静的クラスを使用して、インスタンス データに対して動作しないユーティリティ メソッドを整理します。
static class MathHelpers
{
public static double CircleCircumference(double radius) =>
2 * Math.PI * radius;
}
double circumference = MathHelpers.CircleCircumference(5.0);
Console.WriteLine($"Circumference: {circumference:F2}"); // Circumference: 31.42
.NET クラス ライブラリには、Math や Console など、多くの静的クラスが含まれています。 静的クラスは暗黙的にシールされます。 そこから派生したり、インスタンス化したりすることはできません。
オブジェクト初期化子
オブジェクト初期化子 を使用すると、値の組み合わせごとにコンストラクターを書き込まずに、オブジェクトを作成するときにプロパティを設定できます。
class ConnectionOptions
{
public string Host { get; init; } = "localhost";
public int Port { get; init; } = 80;
public bool UseSsl { get; init; }
}
var options = new ConnectionOptions
{
Host = "db.example.com",
Port = 5432,
UseSsl = true
};
Console.WriteLine($"{options.Host}:{options.Port} (SSL: {options.UseSsl})");
// db.example.com:5432 (SSL: True)
オブジェクト初期化子は、 set または init アクセサーを持つ任意のアクセス可能なプロパティで動作します。 これらは、 required プロパティと、呼び出し元が他のパラメーターを設定できるようにしながら、いくつかのパラメーターを受け入れるコンストラクターと自然に組み合わせます。
プロパティが コレクションの場合は、 Collection 式 (C# 参照) を使用してそのオブジェクトを初期化できます。
継承
クラスは 継承をサポートします。 既存のクラスの動作を再利用、拡張、または変更する新しいクラスを定義できます。 継承元のクラスは 基底クラスであり、新しいクラスは 派生クラスです。
var manager = new Manager("Satya", "Engineering");
Console.WriteLine($"{manager.Name} manages {manager.Department}");
// Satya manages Engineering
クラスは、1 つの基底クラスから継承し、複数のインターフェイスを実装できます。 派生クラスは、コンストラクターを除く基底クラスのすべてのメンバーを継承します。 詳細については、「 継承 と インターフェイス」を参照してください。
こちらも参照ください
.NET