web-dev-qa-db-ja.com

C#の参照型

このコードを考えてみましょう:

public class Program
{
    private static void Main(string[] args)
    {
        var person1 = new Person { Name = "Test" };
        Console.WriteLine(person1.Name);

        Person person2 = person1;
        person2.Name = "Shahrooz";
        Console.WriteLine(person1.Name); //Output: Shahrooz
        person2 = null;
        Console.WriteLine(person1.Name); //Output: Shahrooz
    }
}

public class Person
{
    public string Name { get; set; }
}

明らかに、person1person2に割り当て、person2Nameプロパティを変更すると、person1Nameも変更されます。 person1person2は同じ参照を持っています。

person2 = nullの場合、person1変数もnullにならないのはなぜですか?

78
user1968030

personperson2はどちらも同じオブジェクトへの参照です。しかし、これらは異なる参照です。だからあなたが走っているとき

person2 = null;

参照person2のみを変更し、参照personと対応するオブジェクトは変更しません。

これを説明する最良の方法は、簡略化した図を使用することです。これは、beforeのような状況でしたperson2 = null

Before null assignment

そして、これがヌル代入後の画像です:

Enter image description here

ご覧のとおり、2番目の画像ではperson2は何も参照していません(厳密にはnullを参照しています。参照なしとnullへの参照は異なる条件であるため、 Rune FS )、personは既存のオブジェクトを参照しています。

183
Andrei

_person1_および_person2_を、ストレージ内の特定の場所へのポインターと見なします。最初のステップでは、ストレージからのオブジェクトのアドレスを保持しているのは_person1_のみであり、ストレージからのオブジェクトのメモリロケーションのアドレスを保持しているのは後で_person2_です。後で_nullを_person2_に割り当てても、_person1_は影響を受けません。そのため、結果が表示されます。

あなたは読むことができます: ジョセフアルバハーリからの値対参照型

ただし、参照型の場合、オブジェクトはメモリ内に作成され、ポインタのようにではなく、別の参照を通じて処理されます。

次の図を使用して、同じ概念を描こうとします。

enter image description here

タイプpersonの新しいオブジェクトを作成し、_person1_参照(ポインター)がストレージ内のメモリー位置を指しています。

enter image description here

ストレージ内で同じ参照を指す新しいreference(pointer)_person2_を作成しました。

enter image description here

_person2_を介してオブジェクトプロパティNameを新しい値に変更しました。両方の参照が同じオブジェクトを指しているため、Console.WriteLine(person1.Name);Shahroozを出力します。

enter image description here

_person2_参照にnullを割り当てた後、それは何も指していませんが、_person1_はまだオブジェクトへの参照を保持しています。

(最後に、メモリ管理では、 スタックは実装の詳細、パート1 および スタックは実装の詳細、パート2 から表示されます。リペルト)

55
Habib

person2を参照nullに変更しましたが、person1はそこで参照していません。

つまり、代入の前にperson2person1を見ると、どちらも同じオブジェクトを参照しています。次に、person2 = nullを割り当てます。これで、人物2は別のタイプを参照しています。 person2が参照されているオブジェクトは削除されませんでした。

私はそれを説明するためにこのgifを作成しました:

enter image description here

14

参照をnullに設定したからです。

nullへの参照を設定すると、参照自体はnull ..です。参照するオブジェクトではありません。

それらを0からのオフセットを保持する変数と考えてください。personの値は120です。person2の値は120です。オフセット120のデータはPersonオブジェクトです。これを行うと:

person2 = null;

..効果的に言っている、person2 = 0;。ただし、personの値は120のままです。

13
Simon Whitehead

personperson2の両方が同じオブジェクトを指す。したがって、どちらか一方の名前を変更すると、両方が変更されます(メモリ内の同じ構造を指すため)。

しかし、person2nullに設定すると、person2をnullポインターにして、同じpointにならないようにしますpersonとしてのオブジェクトはもうありません。オブジェクト自体を破壊してオブジェクトを破壊することはなく、personはまだオブジェクトをポイント/参照しているため、ガベージコレクションによって強制終了されることはありません。

person = nullも設定し、他にオブジェクトへの参照がない場合、最終的にはガベージコレクターによって削除されます。

4

参照型はオブジェクトIDを保持していると考えるのが最も役立ちます。クラス型Carの変数がある場合、ステートメントmyCar = new Car();はシステムに新しい車を作成してそのIDを報告するように要求します(オブジェクト#57だとしましょう)。次に、「オブジェクト#57」を変数myCarに入れます。 Car2 = myCar;、「オブジェクト#57」を変数Car2に書き込みます。 car2.Color = blue;、それはシステムにCar2で識別された車(オブジェクト#57など)を見つけて青く塗るように指示します。

オブジェクトIDで直接実行される唯一の操作は、新しいオブジェクトの作成とIDの取得、「空白」のID(つまりnull)の取得、オブジェクトIDを保持できる変数または格納場所へのオブジェクトIDのコピー、オブジェクトIDが一致する(同じオブジェクトを参照する)。他のすべての要求は、IDによって参照されるオブジェクトを見つけて、そのオブジェクトに作用するようにシステムに要求します(IDまたはIDを保持する他のエンティティに影響を与えることなく)。

.NETの既存の実装では、オブジェクト変数はガベージコレクションされたヒープに格納されたオブジェクトへのポインターを保持する可能性がありますが、オブジェクト参照と他の種類のポインターの間に重大な違いがあるため、これは役に立たない実装の詳細です。ポインターは、通常、操作するのに十分な長さの間置かれるものの場所を表すと想定されています。オブジェクト参照にはありません。コードの一部は、アドレス0x12345678にあるオブジェクトへの参照を含むSIレジスターをロードし、それを使用し始め、ガベージコレクターがオブジェクトをアドレス0x23456789に移動している間に中断される場合があります。それは災害のように聞こえますが、ゴミはコードに関連付けられたメタデータを調べ、コードがSIを使用して使用していたオブジェクトのアドレス(つまり0x12345678)を保持していることを確認し、0x12345678にあったオブジェクトが移動されたことを確認します0x23456789に変更し、SIを更新して0x23456789が戻る前に保持します。そのシナリオでは、SIに格納されている数値はガベージコレクターによって変更されましたが、移動前と移動後は同じオブジェクトを参照していることに注意してください。移動前に、プログラムの起動以降に作成された23,592番目のオブジェクトを参照している場合は、その後も継続します。興味深いことに、.NETはほとんどのオブジェクトの一意で不変の識別子を格納しません。プログラムのメモリの2つのスナップショットが与えられた場合、最初のスナップショットの特定のオブジェクトが2番目のスナップショットに存在するかどうか、またはそのトレースがすべて破棄され、新しいオブジェクトが作成された場合、すべての観察可能な詳細。

2
supercat

person1person2は同じメモリアドレスを指します。 person2をnullにすると、メモリアドレスではなく参照がnullになるため、person1はそのメモリアドレスを参照し続けます。それが理由です。 Classs PersonStructに変更すると、動作が変わります。

2

structに変更すると、値のセマンティクスを取得できることに注意してください。

public class Program
{
    static void Main()
    {
        var person1 = new Person { Name = "Test" };
        Console.WriteLine(person1.Name);

        Person person2 = person1;
        person2.Name = "Shahrooz";
        Console.WriteLine(person1.Name);//Output:Test
        Console.WriteLine(person2.Name);//Output:Shahrooz
        person2 = new Person{Name = "Test2"};
        Console.WriteLine(person2.Name);//Output:Test2

    }
}
public struct Person
{
    public string Name { get; set; }
}
1
Mark Hurd

参照タイプを作成すると、すべてのオブジェクトが同じメモリ位置を指すように実際に参照がコピーされます。ただし、Person2 = Nullを割り当てた場合、person2は参照人のコピーであり、次のようになるだけなので、効果はありません参照のコピーを消去

1
Suraj Singh

person1とperson2は、ヒープ上の同じPersonオブジェクトを指す、スタック上の2つの個別の参照です。

参照の1つを削除すると、スタックから削除され、ヒープ上のPersonオブジェクトをポイントしなくなります。他の参照はそのまま残り、ヒープ上の既存のPersonオブジェクトを指しています。

Personオブジェクトへのすべての参照が削除されると、最終的にはガベージコレクターがオブジェクトをメモリから削除します。

1
Ryan Spears

まず、person1への参照をperson2にコピーします。これで、person1person2は同じオブジェクトを参照します。つまり、そのオブジェクトの値の変更(つまり、Nameプロパティの変更)は、両方の変数で確認できます。次に、nullを割り当てると、person2に割り当てた参照が削除されます。現在person1にのみ割り当てられています。参照自体がnotに変更されていることに注意してください。

参照によって引数を受け入れる関数がある場合、reference to person1by referenceを渡すことができ、参照自体を変更できます。

public class Program
{
    private static void Main(string[] args)
    {
        var person1 = new Person { Name = "Test" };
        Console.WriteLine(person1.Name);

        PersonNullifier.NullifyPerson(ref person1);
        Console.WriteLine(person1); //Output: null
    }
}


class PersonNullifier
{
    public static void NullifyPerson( ref Person p ) {
        p = null;
    }
}

class  Person {
    public string Name{get;set;}
}
0
Asad Saeeduddin
public class Program
{
    private static void Main(string[] args)
    {
        var person = new Person {Name = "Test"};
        Console.WriteLine(person.Name);

        Person person2 = person;
        person2.Name = "Shahrooz";
        Console.WriteLine(person.Name);//Output:Shahrooz
        // Here you are just erasing a copy to reference not the object created.
        // Single memory allocation in case of reference type and  parameter
         // are passed as a copy of reference type .   
        person2 = null;
        Console.WriteLine(person.Name);//Output:Shahrooz

    }
}
public class Person
{
    public string Name { get; set; }
}
0
Suraj Singh

言う:

_person2.Name = "Shahrooz";
_

_person2_の参照に従い、参照がたまたまもたらすオブジェクトを "変更"(変更)します。参照自体(_person2_の)は変更されていません。同じ「アドレス」で同じインスタンスを参照しています。

次のように_person2_に割り当てます:

_person2 = null;
_

referenceを変更します。オブジェクトは変更されません。この場合、参照矢印は1つのオブジェクトから「何もない」nullに「移動」します。しかし、person2 = new Person();のような割り当ても、参照のみを変更します。オブジェクトは変更されません。

0