2009-02-23 7 views
11

많은 디버깅 시간이 복잡한 명령문에서 null 참조 예외를 추적하는 데 소비되는 것으로 보입니다. 예를 들면 : 나는 NullReferenceException이를 얻을 때Null 참조가있는 개체에 Null 참조 예외의 이름을 지정할 수없는 이유는 무엇입니까?

For Each game As IHomeGame in _GamesToOpen.GetIterator() 

왜, 내가 줄 스택 추적에서 수 있지만 널 (null)에 해당 개체의 이름을 얻을 수 있습니다. 익명 성을 보호하기 위해 의미

game was set to null. 

이 엄격하게 디자인 선택

Object reference not set to an instance of an object. 

대신

_GamesToOpen is not set to an instance of an object. 

또는

Anonymous object returned by _GamesToOpen.GetIterator() is null. 

또는

, 왜 즉, 또는 코드가 있습니다. 디버깅 시간 예외에이 정보를 포함하지 않는 컴파일러 디자인의 이유는 무엇입니까?

답변

11

예외는 런타임 항목이며, 변수는 컴파일 시간의 것입니다.

실제로 예제의 변수는 이고 표현식은입니다. 표현식은 항상 단순한 변수는 아닙니다. 런타임에 표현식이 평가되고 메소드가 결과 객체에서 호출됩니다. 해당 표현식의 값이 null이면 런타임에 NullReferenceException이 발생합니다.

Dim a as New MyObject 
Dim b as String = MyObject.GetNullValue().ToString() 

어떤 오류 메시지가 GetNullValue() 방법은 null을 런타임 수익을 반환하는 경우는 다음을 가정?

+2

줄 번호는 런타임 문제이기도합니다. 디버그 시간 컴파일에는 모든 종류의 컴파일 타임 (클래스 및 메소드 이름, 행 번호 등)이 포함됩니다. 왜 변수 이름이 아닌가? –

+1

클래스와 메서드 및 매개 변수 이름은 실제로 IL 수준에서 존재합니다. 그러나 변수는 생성 된 일리노이에서 거의 사라졌습니다. 기본적으로 예외를 특정 변수와 관련시키는 구체적인 방법은 없습니다. "if (a

+0

위의 이유 때문에 허용되었습니다. –

1

개체를 사용하기 전에 Assert 문을 배치하기위한 디버깅을 위해이 코드를 잡는 간단한 방법은 null을 확인하고 의미있는 메시지를 출력하십시오.

+0

Assert를 항상 사용할 수있는 것은 아닙니다. 예를 들어, Linq 표현식 내에 어설 션을 추가 할 수 없습니다. –

+0

내가 틀렸다면 저를 고쳐주세요.하지만 Assert 문은 최적화 된 릴리스 빌드에서 제거 된 것 같습니다. – Marc

1

릴리스 빌드에서 심볼에서 변수 이름이 제거되고 코드가 변수의 특정 메모리 위치를 갖지 않도록 최적화 될 수도 있지만 범위에 따라 레지스터 중 하나에 참조가 유지됩니다 가변 사용법). 따라서 참조 위치에서 변수의 이름을 공제하지 못할 수도 있습니다.

디버그 빌드에는 변수에 대한 자세한 정보가 있습니다. 그러나 예외 객체는 빌드 풍미에 관계없이 동일한 방식으로 작동해야합니다. 따라서, 그것은 어떤 향미든지에서 접근 할 수있는 최소한도 정보에 작동한다.

+0

괜찮습니다. 어쨌든 릴리스 빌드에서는이 파일을 원하지 않을 것입니다. 나는 왜 당신이 디버그 빌드에서 이것을 볼 수 없는지 궁금해했다. –

+0

나는 이것을 언급했지만. 예외 객체는 디버깅 기능이 아니므로 빌드 풍미에 관계없이 동일하게 작동해야합니다. 당신은 Debug class flavor에 따라 String 클래스의 동작이 근본적으로 바뀌 길 기대하지 않겠습니까? –

1

몇 가지 ...

1) 할 때 자신의 예외는 짜증이 있다면 당신은 다른 뭔가를 할 경우는 다른 사람이 누군가에 화가 될 것입니다 위해 (이 점을 명심). 예외 경로가 전형적인 경로가되어서는 안되며, 예외 처리에 소비 된 시간은 유용한 정보를 얻을 가치가 있습니다.

2) 일반적인 프로그래밍 practive으로이 스타일을 채택하고 네 코드 라인의 측면에서 더 길어질 수 있습니다,하지만 당신은 많은 시간을) 저장합니다 (훨씬 적은 문제가됩니다

a)에 결코 do ab(). c(); do x = a.b(); 엑스.기음(); (별개의 행에), a가 null인지 또는 a.b()의 반환이 null인지를 알 수 있습니다.

b) 매개 변수로 메서드 호출을 반환하지 마십시오. 항상 변수를 전달합니다. a (foo()); x = foo();가되어야합니다. 도끼); 이것은 디버깅과 값을 볼 수있는 기능입니다.

.net 및 Java와 같은 환경에서 이러한 종류의 예외에 대한 자세한 정보가있는 런타임 버전이 제공되지 않는 이유가 무엇인지 알지 못합니다 (예 : 인덱스가 범위를 벗어난 배열에 있었던 경우, 이름 null의 변수, 등등 ...의

VM에 의해 해석됩니다 바이트 코드로 컴파일 된 자바와 같은 언어의
2

, 당신은 필드 x와 클래스 X 있다고 가정하고, 그 값은에 대한 null입니다 특정 참조. 당신이

x.foo() 

를 작성하는 경우 바이트 코드는 다음과 같습니다

push Xref   >> top of stack is ref to instance of X with X.x = null 
getField x   >> pops Xref, pushes 'null' on the stack 
invokeMethod foo >> pops 'null' -> runtime exception 

점 스택에 null이 아닌 참조를 필요로하는 작업이 예에서 invokeMethod처럼, 그것을 작동하는 것입니다 , null 참조가 어디에서 왔는지 알 수 없습니다.