[c#] 개체 참조가 개체의 인스턴스로 설정되지 않았습니다. .NET에서 어떤 개체가 ‘null’인지 표시하지 않는 이유는 무엇입니까?

이 .NET 처리되지 않은 예외 메시지와 관련하여 :

개체 참조가 개체의 인스턴스로 설정되지 않았습니다.

.NET에서 어떤 객체가 표시되지 않는 이유는 무엇 null입니까?

null오류를 확인 하고 해결할 수 있다는 것을 알고 있습니다 . 그러나 .NET이 어떤 개체에 null 참조가 있고 어떤식이 NullReferenceException?



답변

(Visual Studio 2017의 새로운 예외 도우미에 대한 자세한 내용은이 답변의 끝 부분을 참조하세요.)


이 코드를 고려하십시오.

String s = null;
Console.WriteLine(s.Length);

이것은 NullReferenceException두 번째 줄에 a 를 던지고 s예외가 throw되었을 때 .NET 이 null 이라고 말하지 않는 이유를 알고 싶습니다 .

정보를 얻지 못하는 이유를 이해하려면 실행하는 것이 C # 소스가 아니라 IL이라는 점을 기억해야합니다.

IL_0001 : ldnull
IL_0002 : stloc.0 // 초
IL_0003 : ldloc.0 // 초
IL_0004 : callvirt System.String.get_Length
IL_0009 : System.Console.WriteLine 호출

callvirt를 throw하는 것은 opcode이며 NullReferenceException평가 스택의 첫 번째 인수가 null 참조 (를 사용하여로드 된 참조) 일 때이를 수행합니다 ldloc.0.

.NET이 그것이 snull 참조라는 것을 알 수 있어야한다면 어떤 식 으로든 평가 스택의 첫 번째 인수가 form에서 시작되었음을 추적해야합니다 s. 이 경우 그것이 snull이라는 것을 쉽게 알 수 있지만 값이 다른 함수 호출의 반환 값이고 어떤 변수에도 저장되지 않은 경우 어떻게 될까요? 어쨌든 이러한 종류의 정보는 .NET 가상 머신과 같은 가상 머신에서 추적하려는 정보가 아닙니다.


이 문제를 방지하려면 모든 공용 메서드 호출에서 인수 null 검사를 수행하는 것이 좋습니다 (물론 null 참조를 허용하지 않는 한).

public void Foo(String s) {
  if (s == null)
    throw new ArgumentNullException("s");
  Console.WriteLine(s.Length);
}

메소드에 null이 전달되면 문제가 무엇인지 정확하게 설명하는 예외가 발생합니다 (즉, snull).


4 년 후 Visual Studio 2017에는 a NullReferenceException가 throw 될 때 null이 무엇인지 알려주는 새로운 예외 도우미가 있습니다. null 인 메서드의 반환 값일 때 필요한 정보를 제공 할 수도 있습니다.

Visual Studio 2017 예외 도우미

이것은 DEBUG 빌드에서만 작동합니다.


답변

다음과 같은 경우 오류 메시지를 어떻게 표시 하시겠습니까?

AnyObject.GetANullObject().ToString();

private object GetANullObject()
{
  return null;
}

여기에보고 할 변수 이름이 없습니다!


답변

음, Microsoft의 엔지니어가 대답해야합니다. 그러나 분명히 디버거를 사용하고 시계를 추가하여 어느 것이 문제가 있는지 알아낼 수 있습니다.

그러나 예외는 NullReferenceException참조 가 존재하지 않음 을 의미 합니다 . 전혀 생성되지 않은 개체는 가져올 수 없습니다.

but why .NET don't tell us which object is null?
어떤 객체가 null인지 모르기 때문입니다. 개체는 단순히 존재하지 않습니다!

C #이 .NET IL 코드로 컴파일되었다고 말할 때도 마찬가지입니다. .NET IL 코드는 이름이나 식을 알지 못합니다. 참조와 위치 만 알고 있습니다. 여기에서도 존재하지 않는 것을 얻을 수 없습니다. 표현식 또는 변수 이름이 없습니다.

철학 : 애초에 달걀이 없으면 오믈렛을 만들 수 없습니다.


답변

확실하지는 않지만 .Net이 미리 정의 된 클래스인지 사용자 정의인지 알지 못하기 때문일 수 있습니다. 미리 정의 된 경우 null (예 : 2 바이트를 차지하는 문자열)이 될 수 있지만 사용자가 정의한 경우 인스턴스를 만들어야이 개체가이 정도의 메모리를 차지한다는 것을 알 수 있습니다. 따라서 런타임에 오류가 발생합니다.


답변

좋은 질문. 메시지 상자는 쓸모가 없습니다. 참조 정의에서 1 마일 깊이 묻혀 있어도 일부 클래스 나 어셈블리 또는 파일 또는 기타 정보가 현재 제공하는 것보다 낫습니다 (읽기 :없는 것보다 낫습니다).

가장 좋은 방법은 디버깅 정보와 함께 디버거에서 실행하는 것입니다. 그러면 IDE가 문제가되는 줄에서 중단됩니다 (실제로 유용한 정보를 사용할 수 있음을 명확하게 보여줌).


답변