4

The following code has only thrown a NullReferenceException a handful of times over the last several months, but I'm not exactly sure why. The code isn't mine, but it looks pretty straight forward to me.

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.Dictionary2.Insert(TKey key, TValue value, Boolean add) +210 System.Collections.Generic.Dictionary2.set_Item(TKey key, TValue value) +11

The only thing I can think of is that pageType is null when it's being used as a dictionary key, but apparently that is not possible.

The code that calls it is simple:

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

I also thought that the error might be with the _section.Pages, but section is never null and never sets anything. If .Pages[page] returns null, the MyPage constructor simply returns. So what am I missing?

Community
  • 1
  • 1
Brandon
  • 68,708
  • 30
  • 194
  • 223
  • does your "MyPage" object overide 'GetHashCode' or 'Equals'? Those are two possible calls that the Dictionary class would make on your objects. – Mike Marshall Mar 28 '11 at 16:24

6 Answers6

2

I had this issue and it turned out to be threading related.

By placing a sync lock around the line that inserts into the dictionary you can protect against the error:

This must be added as a class level definition:

private static object _sync = new object();

This is the insert statement surrounded by a sync lock:

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

This is the post that solved it for me: Throw a NullReferenceException while calling the set_item method of a Dictionary object in a multi-threading scenario

Community
  • 1
  • 1
AndyM
  • 21
  • 4
1

I think it is throwing an exception because there is no element in the dictionary for the key pageType, and the accessor is returning null.

Try

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

or if you are trying to reuse the entry if it exists:

MyPage newPage = new MyPage(_section.Pages[page]);
if (_pages.ContainsKey(pageType))
   _pages[pageType] = newPage;
else
   _pages.Add(pageType, newPage);
Mike Marshall
  • 7,788
  • 4
  • 39
  • 63
  • isn't accessing a dictionary by its indexer when it doesn't exist supposed to create the entry? http://en.csharp-online.net/BCL_Generics%E2%80%94Adding_and_Updating_Dictionary_Items – Brandon Mar 28 '11 at 16:02
  • Dictionary indexer setter never throws exceptions when a new element is added. It could be thrown by getter, but in this case, it'd be the KeyNotFoundException, not the NullReferenceException. – Konstantin Oznobihin Mar 28 '11 at 16:04
1

maybe the dictionary user defines somewhere else a custom IEqualityComparer that fails under some circumstances. Check where the code creates the dictionary to see if a custom comparer is passed. Maybe the comparer as well can be null, but this means this code never run...

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
0

I would split them out for clarity, then see whats happening.

var section = _section.Pages[page];
var newPage = new MyPage(section);
_pages.Add(pageType,newPage);
return newPage;
Richard Friend
  • 15,800
  • 1
  • 42
  • 60
  • I have now, but since this error happens very rarely, I have never been able to reproduce or debug it. It usually only shows up in a production environment. – Brandon Mar 28 '11 at 16:12
0

I think either _pages or pageType object is null. Another chance is _section object.

Anuraj
  • 18,859
  • 7
  • 53
  • 79
  • dev, _pages and _section aren't null. There are null checks I removed to keep the example brief. And pageType can't be null, because GetType will never return null. – Brandon Mar 28 '11 at 16:00
  • If the exception is thrown by the provided code neither one of these could be null: _pages and pageType are used above the last line when TryGetValue is called, moreover if pageType would be null the ArgumentNullException would be thrown. The _section couldn't be null as well since we should not get into Dictionary.Insert method in this case. – Konstantin Oznobihin Mar 28 '11 at 16:08
  • @Brandon: actually GetType can return null, if we use proxy intercepting GetType calls, but it doesn't look to be your case indeed. – Konstantin Oznobihin Mar 28 '11 at 16:12
0

Since TryGetValue didn't failed it looks to be caused by _section.Pages[page]. Since exception comes from Dictionary.Insert method, most probably, it's caused by equality/hash code implementation for the page. Are there custom implementations of IEqualityComparer or Equals/GetHashCode methods for page type? How these dictionaries are created?

Konstantin Oznobihin
  • 5,234
  • 24
  • 31
  • the dictionaries are declared as private readonly at the class level. They do not override any of the methods. – Brandon Mar 28 '11 at 16:48
  • @Brandon: how dictionaries are created (not declared)? Do you pass comparer to dictionary constructor? Are there Equals/GetHashCode overrides for page type? Surely, there are no overrides for dictionary, since it doesn't make sense. – Konstantin Oznobihin Mar 28 '11 at 17:17