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


103

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

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

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

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

c#  .net 

2
이 경우 발생한 줄을 다시 작성하여 가능한 각 결과가 null인지 먼저 확인합니다. 그러면 정확히 무엇인지 알 수 있습니다. 또는 Visual Studio의 놀라운 디버거가 연결되어 예외가 발생하는 순간을 중단하고 null이 무엇인지 확인할 수 있습니다. :)
— Patashu

5
실제로는 .NET 프레임 워크가 프로그래머가 어떤 개체가 null 인지 표시 하는 데 도움이되지 않는 이유를 묻습니다 . 나는 그것이 성능 페널티라고 생각합니다 (반영이 필요합니다). 그러나 나도 확실하지 않습니다.
— bas

1
@bas : 사실이지만 질문은 "객체"가 아닌 "표현의 일부"에 대해 질문해야한다는 점에서 약간 오해의 소지가 있습니다. 또한 단순한 리플렉션이 도움이되지 않는 이유를 설명하지만 몇 가지 광범위한 디버그 정보가 필요합니다.
— OR Mapper

4
그래도 답이 궁금합니다. 그것은 .NET 예외와 유사한 지적에 도움이되지 떨어져 종류의 어떤 사전에 존재하지 않는 키를 누릅니다. 또한 질문에 대한 열성 인을 이해하지 못합니다.
— bas

12
용어 설명 : 개체는 null이 아닙니다. 객체 참조는 하지만 수 있습니다. 그러나 객체 참조는 메모리의 한 위치 일뿐입니다. 어쨌든 디버거가 연결되어 있지 않으면 어떻게 도움이 될까요?
— Oskar Berggren 2013

답변:


169

(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 빌드에서만 작동합니다.


5
줄 번호와 소스 파일 이름은 IL 코드 자체에 저장되지 않습니다. 그러나 디버깅에 사용할 수 있습니다.
— OR Mapper

4
@MartinLiversage : 맞습니다. 따라서 질문은 다음과 같이 요약됩니다 null. 코드의 어떤식이 평가되었는지도 알려주는 기호 파일에 저장된 정보가 충분하지 않은 이유는 무엇입니까?
— OR Mapper

2
@MartinLiversage : 예외 발생시 예외 메시지와 함께 소스 파일 및 줄 번호가 디버거의 출력에 표시 될 수 있도록 심볼 파일에 액세스 할 수 있습니다. 따라서 문제는 정확히 반환 된 내용에 대한 추가 정보를 포함하지 않은 이유가 무엇인지 null입니다. OP는 릴리스 빌드의 경우 디버그 빌드로도 충분할 수 있음을 알고 싶어하지 않는다는 점에 유의하십시오.
— OR Mapper

3
흠, 우리는 실제로 실행하는 것은 IL조차 아니라 런타임에 빌드 된 네이티브 코드라는 것을 잊지 말아야합니다.
— Oskar Berggren 2013

2
@MartinLiversage :이 질문의 아무도 우리가 릴리스 빌드에 대해 완벽하게 지원되기를 원한다고 주장하지 않습니다. 어쨌든, 나는 객체 참조를 사용하는 IL opcode를 null그 객체 참조를 반환 한 소스 파일 라인 및 열과 연관시키는 문제를 잘 알지 못합니다 .
— OR Mapper

9

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

AnyObject.GetANullObject().ToString();

private object GetANullObject()
{
  return null;
}

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


2
OP가 개체가 아닌 null을 반환하는 소스 코드에서 표현식을 찾고 있다고 생각합니다. 나는 질문에 각각의 의견을 추가했으며 그가 일을 해결하기를 바랍니다. 내 의심이 맞다면 OP는 Object reference obtained from AnyObject.GetANullObject() not set to an instance of an object.오류 메시지 와 같은 것을 기대할 것 입니다.
— OR Mapper

1
@ORMapper 동의합니다. 댓글을 달 수있는 평판 포인트가 충분하다면 OP에 대한 댓글에 내 "답변"을 넣었을 것입니다!
— romar

1
"XYZ 클래스의 ToString () 메서드를 호출하려는 null 참조"가 지금 얻는 것보다 더 유용 할 것입니다.
— Michael Levy

가장 유용한 것은 각 호출 수준에서 정확히 어떤 줄, 어떤 파일에서 오류가 발생했는지 보여주는 스택 추적입니다. 아, 잠깐만 요 ... 그게 지금하는 일입니다!
— Jim Balter 2015

1

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

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

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

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

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


3
— bas

참조가 존재하지 않는 경우 어떻게 얻습니까? @Bas
— 아니 켓 인게

4
"음, Microsoft의 엔지니어가 대답해야합니다." 그러니 그들이 명백한 말 대신에 이것에 대해 밝히도록하자
— bas

@bas 우리는 적어도 논리적 인 것을 결정할 수 있습니다. 논리적으로 개체가 존재하지 않습니다. 예외를 가지고 그것을 잡은 다음 객체의 이름을 어떻게 인쇄합니까? 존재하지 않습니다. 스택에도 ..
— Aniket Inge 2013

그래서 대답은 그것이 어떤 객체가 nullreference를 가지고 있는지 지적하는 것이 사실상 불가능하다는 것입니다. 그것도 대답입니다. 나는 내가 알고 있다고 말하는 것이 아니라 질문을 좋아합니다 :). 모든 +1 노력 : P
— BAS

1

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


-2

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.