2011-03-28 1 views
4

다음 코드는 지난 몇 개월 동안 NullReferenceException을 던져 줬지만 그 이유는 확실하지 않습니다. 코드는 제 것이 아니지만 제게는 꽤 똑바로 보입니다.사전에 항목을 추가하면 NullReferenceException이 발생합니다.

Type pageType = page.GetType(); 

if (_pages.TryGetValue(pageType, out value)) 
    return value; 

// The following line throws the exception 
return _pages[pageType] = new MyPage(_section.Pages[page]); 

[NullReferenceException: Object reference not set to an instance of an object.] System.Collections.Generic.Dictionary 2.Insert(TKey key, TValue value, Boolean add) +210 System.Collections.Generic.Dictionary 2.set_Item(TKey key, TValue value) +11

내가 생각할 수있는 유일한 방법은 그것을 분명히 that is not possible 사전 키로 사용하지만, 될 때 pageType가 null 것입니다.

심플 호출하는 코드는 :

protected override void OnLoad(EventArgs e) 
{ 
    base.OnLoad(e); 
    _mypage = GetPage(); 
} 

또한 오류가 _section.Pages 함께 할 수 있다고 생각하지만, 섹션은 null는 아무것도 설정하지 않았다. .Pages[page]이 null을 반환하면 MyPage 생성자가 반환됩니다. 그래서 나는 무엇을 놓치고 있습니까?

+0

"MyPage"개체가 'GetHashCode'또는 'Equals'를 (를) 초과합니까? 이 클래스는 Dictionary 클래스가 객체에 대해 수행 할 수있는 두 가지 호출입니다. –

답변

1

페이지 유형에 대한 사전에 요소가없고 접근자가 null을 반환하기 때문에 예외가 발생한다고 생각합니다. 당신이 존재하는 경우 항목을 다시 사용하려는 경우

MyPage newPage = new MyPage(_section.Pages[page]); 
_pages.Add(pageType, newPage); 
return newPage; 

을 시도하거나 :

MyPage newPage = new MyPage(_section.Pages[page]); 
if (_pages.ContainsKey(pageType)) 
    _pages[pageType] = newPage; 
else 
    _pages.Add(pageType, newPage); 
+0

은 항목을 생성하기 위해 존재하지 않는 색인기에 의해 사전에 액세스하지 않습니까? http://en.csharp-online.net/BCL_Generics%E2%80%94Adding_and_Updating_Dictionary_Items – Brandon

+0

사전 인덱서 설정자는 새 요소가 추가 될 때 절대로 예외를 throw하지 않습니다. getter에 의해 throw 될 수 있지만이 경우 NullReferenceException이 아닌 KeyNotFoundException입니다. –

0

나는 일이 뭐죠 다음을 참조 명확성을 위해 그들을 분할 것이다.

var section = _section.Pages[page]; 
var newPage = new MyPage(section); 
_pages.Add(pageType,newPage); 
return newPage; 
+0

지금은 있지만이 오류는 매우 드물게 발생하기 때문에 재현하거나 디버깅 할 수 없었습니다. 일반적으로 프로덕션 환경에서만 나타납니다. – Brandon

0

_pages 또는 pageType 개체가 null 인 것 같습니다. 또 다른 기회는 _section 오브젝트입니다.

+0

dev, _pages 및 _section은 null이 아닙니다. 예제를 간략하게하기 위해 제거한 null 체크가 있습니다. 그리고 GetType은 결코 null을 반환하지 않기 때문에 pageType은 null이 될 수 없습니다. – Brandon

+0

제공된 코드에 의해 예외가 발생하면 TryGetValue가 호출 될 때 마지막 행 위에 _pages 및 pageType이 사용되며, 또한 pageType이 null 인 경우 ArgumentNullException이 발생합니다. _section은 Dictionary.Insert 메소드에 들어가서는 안되기 때문에 null이 될 수 없습니다. –

+0

@Brandon : 실제로 GetType은 프록시 인터셉트 GetType 호출을 사용하는 경우 null을 반환 할 수 있지만 사실은 그렇지 않습니다. –

0

TryGetValue가 실패하지 않았으므로 _section.Pages [page]가 원인 인 것 같습니다. 예외는 Dictionary.Insert 메서드에서 비롯된 것이므로 페이지에 대한 평등/해시 코드 구현 때문에 발생합니다. 페이지 유형에 대한 IEqualityComparer 또는 Equals/GetHashCode 메소드의 사용자 정의 구현이 있습니까? 이 사전들이 어떻게 만들어 졌습니까?

+0

사전은 클래스 수준에서 개인 읽기 전용으로 선언됩니다. 그들은 어떤 방법보다 우선하지 않습니다. – Brandon

+0

@Brandon : 사전이 어떻게 (선언되지 않고) 생성 되었습니까? 사전 생성자에 비교자를 전달합니까? 페이지 유형에 대한 Equals/GetHashCode 재정의가 있습니까? 사전에 대한 우선 적용은 없습니다. 이해가되지 않습니다. –

1

어쩌면 사전 사용자는 다른 곳에서 정의 일부 상황에서 실패 IEqualityComparer 정의합니다. 사용자 지정 비교 자 전달 여부를 확인하려면 코드에서 사전을 만드는 위치를 확인하십시오. 어쩌면 비교 자도 null이 될 수 있지만,이 코드가 실행되지 않을 수도 있음을 의미합니다 ...

2

이 문제가 발생하여 스레딩과 관련이있는 것으로 나타났습니다.

이는 클래스 레벨 정의로 추가해야합니다 : 오류를 방지 할 수있는 사전에 삽입 라인 주위에 동기화 잠금을 배치함으로써

private static object _sync = new object(); 

이 삽입 성명 동기화 잠금으로 둘러싸인 :

lock (_sync) 
{ 
    return _pages[pageType] = new MyPage(_section.Pages[page]); 
} 

이 나를 위해 그것을 해결 포스트는 다음과 같습니다 Throw a NullReferenceException while calling the set_item method of a Dictionary object in a multi-threading scenario

+1

이 링크는 질문에 대답 할 수 있지만 답변의 핵심 부분을 여기에 포함시키고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않게 될 수 있습니다. – djv

+2

좋은 지적 @ 버드 리노. 그에 따라 내 게시물을 편집했습니다. – AndyM