“객체 참조가 객체의 인스턴스로 설정되지 않은”이유는 무엇입니까?


39

우리는 시스템을 시작하고 때로는 NullReferenceException메시지와 함께 유명한 예외 가 발생합니다 Object reference not set to an instance of an object.

그러나 거의 20 개의 객체가있는 방법에서 객체가 null이라는 로그를 갖는 것은 실제로 전혀 사용되지 않습니다. 세미나의 보안 요원 일 때 100 명의 참석자 중 한 명이 테러리스트라고 말하는 것과 같습니다. 그것은 당신에게 전혀 쓸모가 없습니다. 어떤 사람이 위협적인 사람인지 알아 내려면 더 많은 정보를 얻어야합니다.

마찬가지로 버그를 제거하려면 어떤 객체가 null인지 알아야합니다.

이제 몇 달 동안 무언가가 내 마음에 사로 잡혔습니다.

.NET이 왜 이름이나 최소한 객체 참조의 유형 인 null을 제공하지 않습니까? . 반사 또는 다른 출처의 유형을 이해할 수 없습니까?

또한 어떤 객체가 null인지 이해하는 가장 좋은 방법은 무엇입니까? 이러한 컨텍스트에서 항상 개체의 Null 허용 여부를 수동으로 테스트하고 결과를 기록해야합니까? 더 좋은 방법이 있습니까?

업데이트 : 예외 The system cannot find the file specified의 특성은 동일합니다. 프로세스에 연결하고 디버그 할 때까지 어떤 파일을 찾을 수 없습니다. 이러한 유형의 예외가 더 지능적으로 될 수 있다고 생각합니다. .NET이 c:\temp.txt doesn't exist.일반적인 메시지 대신 우리에게 말할 수 있다면 더 좋지 않을까요 ? 개발자로서 나는 찬성 투표합니다.


14
예외는 행 번호가있는 스택 추적을 포함해야합니다. 해당 라인에서 액세스 한 모든 개체를보고 조사를 시작합니다.
PersonalNexus

2
또한 Visual Studio의 예외 도우미 대화 상자에 new클래스의 인스턴스를 만드는 데 사용되는 "유용한"힌트가 포함 된 이유가 항상 궁금했습니다 . 그러한 힌트가 모두 실제로 도움이되는시기는 언제입니까?
PersonalNexus

1
10 개의 객체 호출 체인이있는 경우 디자인에서 커플 링에 문제가 있습니다.
피트 Kirkham


9
나는이 질문에 대한 모든 단일 답변이 "디버거를 사용하고, 오류를 기록하고, null을 확인하십시오. 어쨌든 당신의 잘못입니다." stackoverflow에서만 누군가가 실제로 답변을 제공합니다 (VM이 추적하기에는 너무 많은 오버 헤드라고 생각합니다). 그러나 실제로이 질문에 올바르게 대답 할 수있는 유일한 사람들은 프레임 워크에서 일한 Microsoft의 사람입니다.
Rocklan

답변:


28

NullReferenceException기본적으로 당신을 알려줍니다 당신이 잘못을하고 있습니다. 더 이상 아무것도 없습니다. 반면에 본격적인 디버깅 도구는 아닙니다. 이 경우 두 가지 모두 잘못하고 있다고 말하고 싶습니다.

  • NullReferenceException이 있습니다
  • 왜 / 어떻게 일어 났는지 아는 방식으로 예방하지 않았습니다
  • 그리고 아마도 : 20 개의 객체를 필요로하는 방법이 약간 벗어난 것처럼 보입니다.

나는 일이 잘못되기 전에 모든 것을 점검하고 개발자에게 좋은 정보를 제공하는 것을 좋아합니다. 한마디로 : 사용하여 수표를 쓰고 ArgumentNullException좋아하는 이름을 쓰십시오. 샘플은 다음과 같습니다.

void Method(string a, SomeObject b)
{
    if (a == null) throw ArgumentNullException("a");
    if (b == null) throw ArgumentNullException("b");

    // See how nice this is, and what peace of mind this provides? As long as
    // nothing modifies a or b you can use them here and be 100% sure they're not
    // null. Should they be when entering the method, at least you know which one
    // is null.
    var c = FetchSomeObject();
    if(c == null)
    {
        throw InvalidOperationException("Fetching B failed!!");
    }

    // etc.
}

Code Contracts를 살펴볼 수도 있습니다. 기발한 기능이 있지만 꽤 잘 작동하며 입력을 절약 할 수 있습니다.


17
@SaeedNeamati 당신은 큰 코드베이스를 가지고 있기 때문에 괜찮은 오류 검사를해서는 안된다는 것을 암시하지 않습니다. 프로젝트가 클수록 역할 또는 오류 검사 및보고가 더 중요해집니다.
stijn

6
실제 질문에 대답하지 않더라도 좋은 조언을 얻으려면 +1하십시오 (Anders Hejlsberg 만 대답 할 수 있음).
로스 패터슨

12
훌륭한 조언을 위해 +1. @SaeedNeamati 당신은이 조언을 들어야합니다. 문제는 부주의와 코드의 전문성 부족으로 인해 발생합니다. 좋은 코드를 작성할 시간이 없다면 훨씬 더 큰 문제가 있습니다 ...
MattDavey

3
좋은 코드 를 작성할 시간이 없다면 잘못된 코드 를 작성할 시간이 없습니다 . 잘못된 코드를 작성하면 좋은 코드를 작성하는 것보다 시간이 오래 걸립니다. 실제로 버그에 신경 쓰지 않는 한 . 그리고 정말로 버그에 신경 쓰지 않는다면 왜 프로그램을 작성해야합니까?
MarkJ

5
@SaeedNeamati I only say that checking every object to get sure that it's not null, is not a good method진지하게. 가장 좋은 방법입니다. 그리고 null이 아닌 모든 인수에서 합리적인 값을 확인하십시오. 오류를 일찍 발견하면 원인을 찾기가 더 쉽습니다. 원인 추적을 찾기 위해 스택 추적에서 여러 레벨을 역 추적 할 필요는 없습니다.
jgauffin

19

실제로 전화하려는 것을 정확하게 보여 주어야합니다. "문제가 있습니다. 문제를 해결해야합니다. 문제가 무엇인지 알고 있습니다. 말하지 않을 것입니다. 알아 차리십시오"이 스택 오버플로에 대한 답의 절반은 아이러니하게 들립니다.

예를 들어 이것을 얻는다면 얼마나 유용할까요?

Object reference (HttpContext.Current) not set to instance of an object

...? 코드로 들어가서 코드를 살펴보고 호출하려고하는 null것이 괜찮다 는 것을 알아 내려면 약간의 도움을주는 것이 어떻습니까?

나는 일반적으로 코드를 통해 답을 얻기 위해 유용하지만 (더 많은 것을 알기 때문에) NullReferenceException위의 예와 같이 텍스트가 더 많으면 많은 시간과 좌절이 저장되는 경우가 많다는 데 동의합니다 .

그냥 말해


런타임은 null이 무엇인지 어떻게 알 수 있습니까?

3
런타임에는 제공하는 것보다 많은 정보가 있습니다. 유용한 정보가 무엇이든 제공해야합니다. 그것이 내가 말하는 전부입니다. 귀하의 질문에 대한 답변으로 왜 알 수 없습니까? 당신이 그것에 대한 대답을 알고 있다면 당신은 당신보다 더 나은 의견을 제공 할 수 있습니다.
LiverpoolsNumber9 9

동의, 그리고 KeyNotFoundException다른 많은 성가신에 대해 동일하게 말할 것입니다 ...
sinelaw

실제로 null 역 참조의 경우 CLR 역 참조 방법 (OP의 질문에 대한 Shahrooz Jefri의 의견 덕분)에 한계가있는 것 같습니다.
sinelaw


4

로그에는 스택 추적이 포함되어야합니다. 일반적으로 메소드의 어떤 행에 문제가 있는지에 대한 힌트를 제공합니다. 릴리스 빌드에 PDB 기호를 포함시켜야 오류가 어느 라인에 있는지 알 수 있습니다.

물론,이 경우에는 도움이되지 않습니다.

Foo.Bar.Baz.DoSomething()

텔은 요구하지 않는 등의 코드를 방지하기 위해 원칙적으로 캔의 도움을.

정보가 포함되지 않은 이유에 대해서는 확실하지 않습니다. 최소한 디버그 빌드에서 실제로 원한다면 알아낼 수 있다고 생각합니다. 크래시 덤프를 가져와 WinDBG에서 여는 것이 도움이 될 수 있습니다.


2

콜 체인에 치명적이지 않은 예외적 인 상황을 알리는 도구로 예외가 만들어졌습니다 . 즉, 디버깅 도구로 설계되지 않았습니다.

널 포인터 예외가 디버깅 도구 인 경우, 즉시 프로그램 실행을 중단하여 디버거가 연결할 수있게하여 문제의 행을 바로 가리 킵니다. 이것은 프로그래머에게 사용 가능한 모든 컨텍스트 정보를 제공합니다. (Null 포인터 액세스로 인한 Segfault가 C에서 수행하는 작업은 거의 거칠지 않지만)

그러나 널 포인터 예외는 정상적인 프로그램 플로우에서 발생하고 포착 될 수있는 유효한 런타임 조건으로 설계되었습니다. 따라서 성능 고려 사항을 고려해야합니다. 또한 예외 메시지를 사용자 정의하려면 런타임시 문자열 오브젝트를 작성, 연결 및 파기해야합니다. 따라서 정적 메시지는 틀림없이 빠릅니다.

그래도 런타임은 침해 참조의 이름을 산출하는 방식으로 프로그래밍 될 수 없다고 말하지 않습니다. 그렇게 할 수 있습니다. 예외를 훨씬 더 느리게 만듭니다. 누군가가 충분히 돌보면 그러한 기능을 전환 가능하게하여 프로덕션 코드를 늦출 수는 없지만 디버깅이 더 쉬워집니다. 그러나 어떤 이유로 든 아무도 돌보지 않은 것 같습니다.


1

Cromulent는 제 생각에 머리에 못을 박았지만, 얻는다면 NullReferenceException초기화되지 않은 변수 가 있다는 명백한 포인트가 있습니다 . 메소드에 전달되는 20 개의 객체에 대한 주장은 완화라고 할 수 없습니다. 코드 청크의 작성자는 코드 코드의 나머지 부분에 대한 준수를 포함하여 수행해야 할 작업을 책임 져야합니다. 변수의 적절하고 정확한 활용 등

그것은 번거롭고 지루하며 때로는 둔하지만 가치가 있습니다. 많은 시간이 몇 기가 바이트에 이르는 로그 파일을 통해 트래킹해야했던 때이며 거의 항상 도움이됩니다. 그러나 그 단계에 도달하기 전에 디버거가 당신을 도울 수 있으며, 그 단계 이전에 좋은 계획은 많은 고통을 덜어 줄 것입니다 (그리고 나는 간단한 스케치와 일부 노트는 할 수 있습니다. 아무것도 아닌 것보다 낫습니다).

Object reference not set to an instance of an object코드와 관련하여 우리가 원하는 값을 추측 할 수 없습니다 : 그것은 프로그래머로서의 일이며, 초기화되지 않은 변수를 전달했음을 의미합니다.


당신은 어셈블리 언어로 작성하기 위해 이와 같은 칭찬을 제공했던 사람들을 알고 있습니까? 자동 가비지 수집을 사용하지 않습니까? 그리고 16 진수로 산술을 할 수 있습니까? "유쾌하고 지루하며 때로는 둔하다"는 자동화해야 할 작업을 설명하는 방법입니다.
Spike0xff

0

디버거 사용법을 배웁니다. 이것은 정확히 설계된 것입니다. 문제의 방법에 중단 점을 설정하고 멀리하십시오.

코드를 단계별로 살펴보고 특정 시점의 모든 변수 값이 정확히 무엇인지 확인하십시오.

편집 : 솔직히 다른 사람이 아직 디버거를 사용하지 않았다는 것에 놀랐습니다.


2
디버거를 사용할 때 모든 예외를 쉽게 재현 할 수 있다고 말하는 것입니까?
jgauffin

@jgauffin 나는 디버거를 사용하여 문제의 코드를 실제로 완전히 테스트하지 못할 수도있는 합성 단위 테스트 대신 실제 코드에서 예외가 발생하는 이유를 알 수 있거나 단위 테스트 자체에 버그가있을 수 있다고 말하고 있습니다. 실제 코드에서 버그를 그리워합니다. 디버거는 내가 생각할 수있는 다른 도구 (Valgrind 또는 DTrace와 같은 것 제외)에 비해 우월합니다.
Cromulent 2019

1
우리는 항상 실패한 컴퓨터에 액세스 할 수 있고 디버깅이 단위 테스트보다 낫다는 것을 말하고 있습니까?
jgauffin

@jgauffin 선택의 여지가 있다면 다른 도구보다 디버거를 선호합니다. 물론 선택의 여지가 없다면 약간의 출발이 아닙니다. 분명히 이것은이 질문의 경우가 아니기 때문에 내가 한 대답을 한 이유입니다. 질문이 원격 디버깅 (또는 로컬 디버깅)을 수행 할 수있는 방법이없는 클라이언트 컴퓨터 에서이 문제를 어떻게 해결 했습니까? 내 대답은 달랐을 것입니다. 당신은 당면한 질문과 관련이없는 방식으로 내 대답을 왜곡하려고하는 것 같습니다.
Cromulent

0

@stijn의 답변을 원하고 코드에 null 검사를 넣고 싶다면이 코드 스 니펫이 도움이 될 것입니다. 다음은 코드 스 니펫에 대한 정보 입니다. 이 설정을 마치면을 입력 argnull하고 tab을 두 번 누른 다음 빈칸을 채우십시오.

<CodeSnippet Format="1.0.0">
  <Header>
    <Title>EnsureArgNotNull</Title>
    <Shortcut>argnull</Shortcut>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>argument</ID>
        <ToolTip>The name of the argument that shouldn't be null</ToolTip>
        <Default>arg</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp">
      <![CDATA[if ($argument$ == null) throw new ArgumentNullException("$argument$");$end$]]>
    </Code>
  </Snippet>
</CodeSnippet>

참고 : c # 6에는 nameof스 니펫이 throw new ArgumentNullException(nameof($argument$))포함되어있어 마법 상수를 포함하지 않고 컴파일러에서 확인하고 리팩토링 도구를 사용하여 더 잘 작업 할 수 있는 이점이 있습니다.
stijn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.