简体   繁体   中英

C# - “Object reference not set to an instance of an object”

I'm currently trying to check if a reference is null before it is used by 'MyMethod' with:

if (School.ClassRoom.Pupil.Age != null)
        {
            MyMethod(School.ClassRoom.Pupil.Age);
        }

However, I'm still getting the "Object reference not set to an instance of an object" on the first line because not only is the Age null, but also the Pupil and ClassRoom are sometimes null too.

I'm getting the same problems using Try, Catch, Finally, since I get the same error in the Try piece of code.

I don't want to have to check each ClassRoom for null, and then each Pupil for null, and then each Age for null each time I want to use this method.

Is there an easier way to do this?

Note: the answer below was written in 2010, long before the null conditional operator was introduced in C# 6.


It sounds like you're after something like Groovy's null-safe dereferencing operator, which would let you write if (School?.ClassRoom?.Pupil?.Age != null) - but C# didn't have such a thing before C# 6.

I'm afraid you have to check each property for nullity, assuming it can be null:

if (School != null && School.ClassRoom != null && School.ClassRoom.Pupil != null
    && School.ClassRoom.Pupil.Age != null)
{
    MyMethod(School.ClassRoom.Pupil.Age);
}

Of course, you could put this whole if block including the method call itself in a helper method, and just call that.

That's assuming it's valid for each property to be null to start with. If you are able to design your classes so that null values aren't even allowed - and you validate this in contsructors etc - your code is likely to end up being a lot cleaner.

It's worth noting that there are two alternative approaches here - the one put forward by Chris in another answer is to create a "default" object for each property; I usually find that it's better to always require a "real" value to be provided in a constructor. Default objects without real data can end up causing bugs which are harder to track down than NullReferenceException problems, as you can happily go along with the "dummy" data for a long time, and just get the wrong result at the end. There are definitely times where it is the right thing to do, however - particularly when it comes to collections. It depends on the situation.

EDIT: Saeed has suggested an extension method in the comments. I assume this would be something like:

public static int? PupilAgeOrNull(this School school)
{
    return school != null && 
           school.ClassRoom != null && 
           school.ClassRoom.Pupil != null
           ? school.ClassRoom.Pupil.Age : null;
}

(Adjust for types appropriately.)

I definitely prefer the idea of trying to keep things non-null elsewhere, but this will do it if you need it. It feels wrong to me though. At the heart of this gut feeling is the fact that you're navigating three or four properties to start with - this feels like a violation of the Law of Demeter to me. Now I'm not one to get dogmatic about such things, but putting an extension method on School feels far too specific to me, for such a long path of properties.

Another alternative - which is also somewhat nasty, IMO - is to write three different extension methods:

public static ClassRoom ClassRoomOrNull(this School school)
{
    return school == null ? null : school.ClassRoom;
}

public static Pupil PupilOrNull(this ClassRoom classRoom)
{
    return classRoom == null ? null : classRoom.Pupil;
}

public static int? AgeOrNull(this Pupil pupil)
{
    return pupil == null ? null : pupil.Age;
}

Then you can write:

int? age = School.ClassRoomOrNull().PupilOrNull().AgeOrNull();
if (age != null)
{
    MyMethod(age);
}

This means that the extension method on School isn't nearly so specific. You've still got a long chain of method calls, and I'd still try to redesign to avoid this situation if possible, but at least there isn't quite such a tight tie from School to School.ClassRoom.Pupil.Age .

Here is a nice and elegant solution with Expression Trees . Try it and enjoy!

Give the code you have shown, there is not an easier way. You will need to check each component.

if (School != null && School.ClassRoom != null 
  && School.ClassRoom.Pupil != null 
  && School.ClassRoom.Pupil.Age != null) 
{
  ...
}

However, you can write your code in such a way that the members are never null . That way you can avoidn having to check for null . For example

class School
{
  private ClassRoom _classRoom = new ClassRoom();

  public ClassRoom ClassRoom 
  {
    get {return _classRoom;}
  }
}

This will give School an empty class room to start with, so it is not null and cannot be set to null outside of the class since the property does not have a setter. You can carry this concept forward, your list of pupils (I assume this would be a list) can be an empty list rather than a null instance etc.

"Null-Object Pattern" comes to your rescue. Read here .

So, you can have NullSchool, NullClassRoom, NullPupil, NullAge.

Then you never need to check for null thing, instead you can have just one check (or method, like IsValid() in Age class, ofcourse virtual) in MyMethod to reject a age if it is not valid.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM