이 코드를 고려하십시오.
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
까지 person2
와 Name
의 속성이 person2
변경되면 Name
의 person1
도 변경됩니다. person1
와 person2
같은 참조를 갖는다.
person2 = null
, person1
변수도 null이 아닌 이유는 무엇 입니까?
답변
둘 다 person
하고 person2
있습니다 참조 같은 객체. 그러나 이들은 다른 참조입니다. 따라서 실행 중일 때
person2 = null;
참조 만 변경 하고 person2
참조 person
및 해당 객체는 변경하지 않습니다.
이것을 설명하는 가장 좋은 방법은 단순화 된 그림이라고 생각합니다. 이전 상황은 다음과 같습니다 person2 = null
.
다음 은 null 할당 후의 그림입니다 .
보시다시피, 두 번째 그림에서는 person2
아무것도 참조하지 않지만 (또는 null
엄격히 말해서, 참조 없음과 참조 null
는 다른 조건이므로 Rune FS의 주석 참조 ), person
여전히 기존 개체를 참조합니다.
답변
고려 person1
와 person2
포인터와 같은 저장 장치의 일부 위치. 첫 번째 단계에서는 person1
저장소에서 객체의 주소 만 보유하고 나중에 person2
는 저장소에서 객체 의 메모리 위치 주소를 보유합니다. 나중에는 할당 할 때 null
에 person2
, person1
숙박 영향을받지 않습니다. 그것이 당신이 결과를 보는 이유입니다.
읽을 수 있습니다 : Joseph Albahari의 Value vs Reference Types
그러나 참조 유형을 사용하면 객체가 메모리에 생성 된 다음 포인터와 같은 별도의 참조를 통해 처리됩니다.
다음 다이어그램을 사용하여 동일한 개념을 묘사하려고합니다.
사람 유형의 새 개체를 만들고 person1
참조 (포인터)가 저장소의 메모리 위치를 가리키고 있습니다.
person2
저장소에서 동일한 것을 가리키는 새로운 참조 (포인터) 를 생성했습니다 .
을 통해 새로운 값으로 객체 속성 명칭 변경 person2
을 모두 참조가 동일한 객체를 가리키는 이후 Console.WriteLine(person1.Name);
출력한다 Shahrooz
.
할당 한 후에 null
을 person2
참조, 그것은 아무것도를 가리키는되지만 person1
여전히 객체에 대한 참조를 들고있다.
(마지막으로 메모리 관리에 대해서는 Eric Lippert의 The Stack Is An Implementation Detail, Part One 및 The Stack Is An Implementation Detail, Part Two 를 참조해야합니다.)
답변
당신은 변했습니다 person2
reference로null
했지만 참조 하고 person1
있지 않습니다.
내 말은 우리가 보면 person2
및 person1
다음 할당을 모두 참조 동일한 개체 전에. 그런 다음을 할당 person2 = null
하면 사람 2가 이제 다른 유형을 참조합니다. person2
참조 된 개체를 삭제하지 않았습니다 .
설명하기 위해이 gif를 만들었습니다.
답변
참조를 설정했기 때문에 null
.
참조를로 설정 null
하면 참조 자체는null
하는 객체 아닙니다.
0에서 오프셋을 유지하는 변수로 생각하십시오 person
. 값 person2
은 120이고 값은 120입니다 Person
. 오프셋 120의 데이터는 객체입니다. 이렇게하면 :
person2 = null;
.. 당신은 효과적으로 말하고 person2 = 0;
있습니다. 그러나 person
여전히 값은 120입니다.
답변
모두 person
와 person2
포인트 같은 객체. 따라서 둘 중 하나의 이름을 변경하면 둘 다 변경됩니다 (메모리의 동일한 구조를 가리 키기 때문에).
사용자가 설정 한 때 person2
에 null
, 당신은 확인 person2
이되지 않습니다 그래서, 널 포인터로 가리키는 과 같은 객체에 person
더 이상. 그것은 그것을 파괴하기 위해 객체 자체에 아무것도하지 않을 것이며, person
여전히 객체를 가리 키거나 참조하기 때문에 가비지 수집에 의해 죽지 않을 것입니다.
을 설정 person = null
하고 객체에 대한 다른 참조가없는 경우 결국 가비지 수집기에 의해 제거됩니다.
답변
person1
와 person2
동일한 메모리 어드레스를 가리킬. null이면 person2
메모리 주소가 아닌 참조가 null이므로 person1
해당 메모리 주소를 계속 참조하므로 그 이유입니다. 당신이를 변경하는 경우 Classs Person
으로 Struct
, 동작이 변경됩니다.
답변
참조 유형을 개체 ID를 보유하는 것으로 생각하는 것이 가장 도움이됩니다. 클래스 유형의 변수가있는 경우 Car
명령문 myCar = new Car();
은 시스템에 새 자동차를 만들고 ID를보고하도록 요청합니다 (객체 # 57이라고 가정 해 보겠습니다). 그런 다음 “object # 57″을 변수에 넣습니다 myCar
. 만약 하나 개 쓰기 Car2 = myCar;
변수 Car2에 “개체 # 57″를 쓴다. 라고 쓰면 car2.Color = blue;
시스템이 Car2 (예 : 객체 # 57)로 식별되는 자동차를 찾고 파란색으로 칠하도록 지시합니다.
객체 ID에서 직접 수행되는 유일한 작업은 새 객체 생성 및 ID 가져 오기, “빈”ID (예 : null) 가져 오기, 객체 ID를 저장할 수있는 변수 또는 저장 위치에 복사, 두 가지 여부 확인입니다. 개체 ID가 일치합니다 (동일한 개체 참조). 다른 모든 요청은 시스템에 ID가 참조하는 객체를 찾고 해당 객체에 대해 조치를 취하도록 요청합니다 (ID를 보유한 변수 또는 기타 엔티티에 영향을주지 않음).
.NET의 기존 구현에서 개체 변수는 가비지 수집 된 힙에 저장된 개체에 대한 포인터를 보유 할 가능성이 있지만 개체 참조와 다른 종류의 포인터간에 중요한 차이가 있기 때문에 구현 세부 사항은 도움이되지 않습니다. 포인터는 일반적으로 작업 할 수있을만큼 오래 머무를 위치를 나타내는 것으로 간주됩니다. 개체 참조는 그렇지 않습니다. 코드 조각은 주소 0x12345678에있는 개체에 대한 참조와 함께 SI 레지스터를로드하고 사용을 시작한 다음 가비지 수집기가 개체를 주소 0x23456789로 이동하는 동안 중단 될 수 있습니다. 그것은 재앙처럼 들리 겠지만, 쓰레기는 코드와 관련된 메타 데이터를 조사 할 것이고, 코드가 SI를 사용하여 그것이 사용하고 있던 객체의 주소를 보유하고 있다는 것을 관찰 할 것입니다 (예 : 0x12345678). 0x12345678에 있던 개체가 0x23456789로 이동되었는지 확인하고 SI를 업데이트하여 반환되기 전에 0x23456789를 유지합니다. 이 시나리오에서 SI에 저장된 숫자 값은 가비지 수집기에 의해 변경되었지만이동 전과 후에 동일한 개체 . 이동하기 전에 프로그램 시작 이후 생성 된 23,592 번째 개체를 참조하는 경우 나중에 계속 그렇게합니다. 흥미롭게도 .NET은 대부분의 개체에 대해 고유하고 변경할 수없는 식별자를 저장하지 않습니다. 프로그램 메모리의 두 스냅 샷이 주어지면 첫 번째 스냅 샷의 특정 개체가 두 번째 스냅 샷에 존재하는지 또는 모든 추적이 취소되고 새 개체가 생성되었는지 여부를 항상 알 수있는 것은 아닙니다. 모든 관찰 가능한 세부 사항.