次の方法で共有


オブジェクト - 型のインスタンスを作成する

クラスまたは構造体の定義は、型で実行できる操作を指定するブループリントに似ています。 オブジェクトは基本的に、ブループリントに従って割り当てられ、構成されたメモリのブロックです。 プログラムは、同じクラスの多くのオブジェクトを作成できます。 オブジェクトはインスタンスとも呼ばれ、名前付き変数または配列またはコレクションに格納できます。 クライアント コードは、これらの変数を使用してメソッドを呼び出し、オブジェクトのパブリック プロパティにアクセスするコードです。 C# などのオブジェクト指向言語では、一般的なプログラムは動的に対話する複数のオブジェクトで構成されます。

静的型の動作は、ここで説明する動作とは異なります。 詳細については、「 静的クラスと静的クラス メンバー」を参照してください。

構造体インスタンスとクラス インスタンス

クラスは参照型であるため、クラス オブジェクトの変数はマネージド ヒープ上のオブジェクトのアドレスへの参照を保持します。 同じ型の 2 番目の変数が最初の変数に割り当てられている場合、両方の変数がそのアドレスにあるオブジェクトを参照します。 この点については、この記事の後半で詳しく説明します。

クラスのインスタンスは、 new 演算子を使用して作成されます。 次の例では、 Person は型、 person1person2 はその型のインスタンスまたはオブジェクトです。

using System;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public Person(string name, int age)
    {
        Name = name;
        Age = age;
    }
    // Other properties, methods, events...
}

class Program
{
    static void Main()
    {
        Person person1 = new Person("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 Person("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
    */
}

p1p2の両方のメモリがスレッド スタックに割り当てられます。 そのメモリは、宣言されている型またはメソッドと共に再利用されます。 これが、割り当て時に構造体がコピーされる理由の 1 つです。 これに対し、クラス インスタンスに割り当てられるメモリは、オブジェクトへのすべての参照がスコープ外になったときに、共通言語ランタイムによって自動的に再利用 (ガベージ コレクション) されます。 C++ の場合と同様に、クラス オブジェクトを確定的に破棄することはできません。 .NET でのガベージ コレクションの詳細については、「 ガベージ コレクション」を参照してください。

マネージド ヒープでのメモリの割り当てと割り当て解除は、共通言語ランタイムで高度に最適化されています。 ほとんどの場合、ヒープにクラス インスタンスを割り当てる場合と、スタックに構造体インスタンスを割り当てる場合のパフォーマンス コストに大きな違いはありません。

オブジェクト ID と値の等価性

2 つのオブジェクトの等価性を比較する場合は、まず、2 つの変数がメモリ内の同じオブジェクトを表すかどうか、または 1 つ以上のフィールドの値が等しいかどうかを確認する必要があります。 値を比較する場合は、オブジェクトが値型 (構造体) のインスタンスであるか、参照型 (クラス、デリゲート、配列) であるかを考慮する必要があります。

  • 2 つのクラス インスタンスがメモリ内の同じ場所 (つまり、同じ ID を持つ) を参照しているかどうかを判断するには、静的 Object.Equals メソッドを使用します。 (System.Object は、ユーザー定義の構造体やクラスを含むすべての値型と参照型の暗黙的な基底クラスです)。

  • 2 つの構造体インスタンスのインスタンス フィールドの値が同じかどうかを判断するには、 ValueType.Equals メソッドを使用します。 すべての構造体は System.ValueTypeから暗黙的に継承されるため、次の例に示すように、オブジェクトでメソッドを直接呼び出します。

    // Person is defined in the previous example.
    
    //public struct Person
    //{
    //    public string Name;
    //    public int Age;
    //    public Person(string name, int age)
    //    {
    //        Name = name;
    //        Age = age;
    //    }
    //}
    
    Person p1 = new Person("Wallace", 75);
    Person p2 = new Person("", 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.ValueTypeEquals実装では、ボックス化やリフレクションが、必要に応じて使用されています。 型に固有の効率的な等値アルゴリズムを提供する方法については、「型の値の 等価性を定義する方法」を参照してください。 レコードは、等価性のために値セマンティクスを使用する参照型です。

  • 2 つのクラス インスタンスのフィールドの値が等しいかどうかを判断するには、 Equals メソッドまたは == 演算子を使用できます。 ただし、その型のオブジェクトにおける「等価性」の意味をカスタム定義するために、クラスがオーバーライドまたはオーバーロードしている場合にのみ使用してください。 クラスは、 IEquatable<T> インターフェイスまたは IEqualityComparer<T> インターフェイスを実装することもできます。 どちらのインターフェイスにも、値の等価性をテストするために使用できるメソッドが用意されています。 Equalsをオーバーライドする独自のクラスを設計するときは、「型とObject.Equals(Object)」に記載されているガイドラインに従ってください。

詳細については、以下を参照してください。