クラスまたは構造体の定義は、型で実行できる操作を指定するブループリントに似ています。 オブジェクトは、プログラムがブループリントに従って割り当てて構成するメモリブロックです。 プログラムは、同じクラスの多数のオブジェクトを作成する場合があります。 オブジェクト インスタンスを呼び出すこともできます。 名前付き変数または配列またはコレクションに格納できます。 クライアント コードでは、これらの変数を使用してメソッドを呼び出し、オブジェクトのパブリック プロパティにアクセスします。 C# などのオブジェクト指向言語では、一般的なプログラムは動的に対話する複数のオブジェクトで構成されます。
注
静的型の動作は、この記事で説明されているものとは異なります。 詳細については、「 静的クラスと静的クラス メンバー」を参照してください。
構造体インスタンスとクラス インスタンス
クラスは参照型であるため、クラス オブジェクトの変数はマネージド ヒープ上のオブジェクトのアドレスへの参照を保持します。 同じ型の 2 番目の変数を最初の変数に割り当てると、両方の変数がそのアドレスにあるオブジェクトを参照します。 この記事では、この点について後で詳しく説明します。
クラスのインスタンスは、 new 演算子を使用して作成します。 次の例では、 Person は型、 person1 、 person2 はその型のインスタンスまたはオブジェクトです。
using System;
public class Person(string name, int age)
{
public string Name { get; set; } = name;
public int Age { get; set; } = age;
// Other properties, methods, events...
}
class Program
{
static void Main()
{
Person person1 = new("Leopold", 6);
Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");
// Declare new person, assign person1 to it.
Person person2 = person1;
// Change the name of person2, and person1 also changes.
person2.Name = "Molly";
person2.Age = 16;
Console.WriteLine($"person2 Name = {person2.Name} Age = {person2.Age}");
Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");
/*
Output:
person1 Name = Leopold Age = 6
person2 Name = Molly Age = 16
person1 Name = Molly Age = 16
*/
}
}
構造体は値型であるため、構造体オブジェクトの変数はオブジェクト全体のコピーを保持します。
new演算子を使用して構造体のインスタンスを作成することもできますが、次の例に示すように、構造体を使用する必要はありません。
using System;
namespace Example
{
public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
public class Application
{
static void Main()
{
// Create struct instance and initialize by using "new".
// Memory is allocated on thread stack.
Person p1 = new("Alex", 9);
Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");
// Create new struct object. Note that struct can be initialized
// without using "new".
Person p2 = p1;
// Assign values to p2 members.
p2.Name = "Spencer";
p2.Age = 7;
Console.WriteLine($"p2 Name = {p2.Name} Age = {p2.Age}");
// p1 values remain unchanged because p2 is copy.
Console.WriteLine($"p1 Name = {p1.Name} Age = {p1.Age}");
}
}
/*
Output:
p1 Name = Alex Age = 9
p2 Name = Spencer Age = 7
p1 Name = Alex Age = 9
*/
}
スレッド スタックは、 p1 と p2の両方にメモリを割り当てます。 プログラムは、そのメモリを宣言する型またはメソッドと共に再利用します。 このメモリ管理は、割り当て時に構造体がコピーされる理由の 1 つです。 これに対し、共通言語ランタイムは、オブジェクトへのすべての参照がスコープ外になると、クラス インスタンスに割り当てるメモリを自動的に再利用 (ガベージ コレクション) します。 C++ のようにクラス オブジェクトを決定的に破棄することはできません。 .NET でのガベージ コレクションの詳細については、「 ガベージ コレクション」を参照してください。
注
共通言語ランタイムは、マネージド ヒープ上のメモリの割り当てと割り当て解除を高度に最適化します。 ほとんどの場合、ヒープにクラス インスタンスを割り当てる場合とスタックに構造体インスタンスを割り当てる場合のパフォーマンス コストに大きな違いはありません。
オブジェクト ID と値の等価性
2 つのオブジェクトの等価性を比較する場合は、最初に、2 つの変数がメモリ内の同じオブジェクトを表すかどうか、または 1 つ以上のフィールドの値が等しいかどうかを判断します。 値を比較する場合は、オブジェクトが値型 (構造体) または参照型 (クラス、デリゲート、配列) のインスタンスであるかどうかを検討します。
静的 Object.ReferenceEquals メソッドを使用して、2 つのクラス インスタンスがメモリ内の同じ場所を参照しているかどうかを判断します (つまり、同じ ID を持つことになります)。 (System.Object は、ユーザー定義の構造体やクラスを含むすべての値型と参照型の暗黙的な基底クラスです)。
既定では、 ValueType.Equals メソッドは、2 つの構造体インスタンスのインスタンス フィールドの値が同じかどうかを判断します。 すべての構造体は System.ValueTypeから暗黙的に継承されるため、次の例に示すように、オブジェクトでメソッドを直接呼び出します。
// Person is defined in the previous example. //public struct Person(string name, int age) //{ // public string Name { get; set; } = name; // public int Age { get; set; } = age; //} Person p1 = new("Wallace", 75); Person p2 = new("", 42); p2.Name = "Wallace"; p2.Age = 75; if (p2.Equals(p1)) Console.WriteLine("p2 and p1 have the same values."); // Output: p2 and p1 have the same values.System.ValueTypeの既定の
Equals実装では、場合によってはボックス化とリフレクションが使用されます。 型に固有の効率的な等値アルゴリズムを提供する方法については、「型を レコードにできない場合に等値を自分で実装する」を参照してください。 レコードは、等価性のために値セマンティクスを使用する参照型です。2 つのクラス インスタンスのフィールドの値が等しいかどうかを判断するには、 Equals メソッドまたは == 演算子を使用できます。 ただし、その型のオブジェクトにおける「等価性」の意味をカスタム定義するために、クラスがオーバーライドまたはオーバーロードしている場合にのみ使用してください。 クラスは、 IEquatable<T> インターフェイスまたは IEqualityComparer<T> インターフェイスを実装することもできます。 どちらのインターフェイスにも、値の等価性をテストするために使用できるメソッドが用意されています。
Equalsをオーバーライドする独自のクラスを設計する場合は、Object.Equals(Object) および で説明されているガイドラインに従ってください。
関連セクション
詳細については、以下を参照してください:
.NET