Programing

C #의 참조 유형

lottogame 2020. 10. 11. 09:05
반응형

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; }
}

물론, 할당 할 때 person1까지 person2Name의 속성이 person2변경되면 Nameperson1도 변경됩니다. person1person2같은 참조를 갖는다.

person2 = null, person1변수도 null이 아닌 이유는 무엇 입니까?


둘 다 person하고 person2있습니다 참조 같은 객체. 그러나 이들은 다른 참조입니다. 따라서 실행 중일 때

person2 = null;

참조 만 변경 하고 person2참조 person및 해당 객체는 변경하지 않습니다.

이것을 설명하는 가장 좋은 방법은 단순화 된 그림입니다. 이전 상황은 다음과 같습니다 person2 = null.

널 할당 전

그리고 다음은 null 할당 후의 그림입니다 .

여기에 이미지 설명 입력

보시다시피, 두 번째 그림에서는 person2아무것도 참조하지 않지만 (또는 null엄격하게 말해서, 참조 없음과 참조 null는 다른 조건이므로 Rune FS의 주석 참조 ), person여전히 기존 개체를 참조합니다.


고려 person1person2 포인터와 같은 저장 장치의 일부 위치. 첫 번째 단계에서는 person1저장소에서 객체의 주소 보유하고 나중에 person2저장소에서 객체 의 메모리 위치 주소를 보유합니다. 나중에는 할당 할 때 nullperson2, person1숙박 영향을받지 않습니다. 그것이 당신이 결과를 보는 이유입니다.

읽을 수 있습니다 : Joseph Albahari의 Value vs Reference Types

그러나 참조 유형을 사용하면 개체가 메모리에 생성 된 다음 포인터와 같은 별도의 참조를 통해 처리됩니다.

다음 다이어그램을 사용하여 동일한 개념을 묘사하려고합니다.

여기에 이미지 설명 입력

사람 유형의 새 개체를 만들고 person1참조 (포인터)가 저장소의 메모리 위치를 가리키고 있습니다.

여기에 이미지 설명 입력

person2저장소에서 동일한 것을 가리키는 새로운 참조 (포인터) 생성했습니다 .

여기에 이미지 설명 입력

을 통해 새로운 값으로 객체 속성 명칭 변경 person2을 모두 참조가 동일한 객체를 가리키는 이후 Console.WriteLine(person1.Name);출력한다 Shahrooz.

여기에 이미지 설명 입력

할당 한 후에 nullperson2참조, 그것은 아무것도를 가리키는되지만 person1여전히 객체에 대한 참조를 들고있다.

(마지막으로 메모리 관리에 대해서는 Eric Lippert의 The Stack Is An Implementation Detail, Part OneThe Stack Is An Implementation Detail, Part Two 를 참조해야합니다.)


person2reference로 변경 null했지만 참조 하고 person1있지 않습니다.

내 말 것은 우리가 보면 person2person1다음 할당을 모두 참조 동일한 개체 전에. 그런 다음을 할당 person2 = null하면 사람 2가 이제 다른 유형을 참조합니다. person2참조 된 개체를 삭제하지 않았습니다 .

설명하기 위해이 gif를 만들었습니다.

여기에 이미지 설명 입력


참조를 null.

에 대한 참조를 설정 null하면 참조 자체는 참조 null하는 객체 아닙니다.

0에서 오프셋을 유지하는 변수로 생각하십시오 person. 값 person2은 120이고 값은 120입니다 Person. 오프셋 120의 데이터는 객체입니다. 이렇게하면 :

person2 = null;

.. 당신은 사실상 person2 = 0;. 그러나 person여전히 값은 120입니다.


모두 personperson2 포인트 같은 객체. 따라서 둘 중 하나의 이름을 변경하면 둘 다 변경됩니다 (메모리의 동일한 구조를 가리 키기 때문에).

사용자가 설정 한 때 person2null, 당신은 확인 person2이되지 않습니다 그래서, 널 포인터로 가리키는 과 같은 객체에 person더 이상. 그것은 그것을 파괴하기 위해 객체 자체에 아무것도하지 않을 것이며, person여전히 객체를 가리 키거나 참조하기 때문에 가비지 수집에 의해 죽지 않을 것입니다.

을 설정 person = null하고 객체에 대한 다른 참조가없는 경우 결국 가비지 수집기에 의해 제거됩니다.


person1person2동일한 메모리 어드레스를 가리킬. null이면 person2메모리 주소가 아닌 참조가 null이므로 person1해당 메모리 주소를 계속 참조하므로 그 이유입니다. 당신이를 변경하는 경우 Classs Person으로 Struct, 동작이 변경됩니다.


I find it most helpful to think of reference types as holding object IDs. If one has a variable of class type Car, the statement myCar = new Car(); asks the system to create a new car and report its ID (let's say it's object #57); it then puts "object #57" into variable myCar. If one writes Car2 = myCar;, that writes "object #57" into variable Car2. If one writes car2.Color = blue;, that instructs the system to find the car identified by Car2 (e.g. object #57) and paint it blue.

개체 ID에 대해 직접 수행되는 유일한 작업은 새 개체 생성 및 ID 가져 오기, "빈"ID (예 : null) 가져 오기, 개체 ID를 저장할 수있는 변수 또는 저장 위치에 복사, 두 가지 여부 확인입니다. 개체 ID가 일치합니다 (동일한 개체 참조). 다른 모든 요청은 시스템에 ID가 참조하는 객체를 찾고 해당 객체에 대해 조치를 취하도록 요청합니다 (ID를 보유한 변수 또는 기타 엔티티에 영향을주지 않음).

In existing implementations of .NET, object variables are likely to hold pointers to objects stored on a garbage-collected heap, but that's an unhelpful implementation detail because there's a critical difference between an object reference and any other kind of pointer. A pointer is generally assumed to represent the location of something which will stay put long enough to be worked with. Object references don't. A piece of code may load the SI register with a reference to an object located at address 0x12345678, start using it, and then be interrupted while the garbage collector moves the object to address 0x23456789. That would sound like a disaster, but the garbage will examine the metadata associated with the code, observe that the code used SI to hold the address of the object it was using (i.e. 0x12345678), determine that object that was at 0x12345678 had been moved to 0x23456789, and update SI to hold 0x23456789 before it returned. Note that in that scenario, the numerical value stored in SI was changed by the garbage collector, but it referred to the same object before the move and afterward. If before the move it referred to the 23,592nd object created since program startup, it will continue to do so afterward. Interestingly, .NET does not store any unique and immutable identifier for most objects; given two snapshots of a program's memory, it will not always be possible to tell whether any particular object in the first snapshot exists in the second, or if all traces to it have been abandoned and a new object created that happens to look like it in all observable details.


person1 and person2 are two separate references on the stack that point to the same Person object on the heap.

When you delete one of the references, it is removed from the stack and no longer points to the Person object on the heap. The other reference remains, still pointing to the existing Person object on the heap.

Once all references to the Person object are removed, then eventually the Garbage Collector will removed the object from memory.


When you create a reference type its actually copying a reference with all objects pointing to the same memory location , However If you have assigned Person2=Null it will have no effect as person2 is just a copy of reference person and we have just erased a copy of reference .


Note that you can get value semantics by changing to a 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; }
}

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; }
}

You first copy the reference to person1 to person2. Now person1 and person2 refer to the same object, which means modifications to the value of that object (i.e changing the Name property) can be observed under both variables. Then, when assigning null, you are removing the reference you just assigned to person2. It is only assigned to person1 now. Note that the reference itself is not changed.

If you had a function that accepted an argument by reference, you could pass reference to person1 by reference, and would be able to change the reference itself:

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;}
}

Saying:

person2.Name = "Shahrooz";

참조를 따르고 person2참조가 발생하는 객체를 "변형"(변경)합니다. 자체 참조합니다 ( 의가 person2) 변경되지 않는다; 우리는 여전히 동일한 "주소"에서 동일한 인스턴스를 참조합니다.

에 할당 person2:

person2 = null;

참조를 변경합니다 . 개체가 변경되지 않습니다. 이 경우 참조 화살표는 한 개체에서 "없음"으로 "이동"됩니다 null. 그러나 같은 할당 person2 = new Person();은 참조 만 변경합니다. 개체가 변경되지 않습니다.

참고 URL : https://stackoverflow.com/questions/18229463/reference-type-in-c-sharp

반응형