2

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?

3
  • How do you fill School.ClassRoom.. data? While filling, dont allow NULL lines may be a solution? Commented Nov 21, 2010 at 8:47
  • Btw, your title doesnt seems appropriate. There is nothing confusing about the exception you are getting. Commented Nov 21, 2010 at 9:13
  • If possible I'd like to be able to continue using null classes since this is part of quite a complex data structure and if I start having new instances of all the nulls then I think the memory usage would go through the roof. Commented Nov 21, 2010 at 9:55

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

10 Comments

he wants do not do this, instead of if write an extension method
@Saeed: Um, where did he mention extension methods?
if (School.IsNullAge()) It's easy to write such a function, why should he mention this, he don't like ugly code
@Saeed: And what's the method going to look like? It'll have basically the same code in. I also doubt that it's the cleanest solution. Admittedly it does only mean writing the code once.
@Saeed: I've added your suggestion to my answer, but it feels wrong to me - I'm editing to explain why.
|
2

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

Comments

1

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.

Comments

1

"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.

1 Comment

Well it may come to the rescue. It depends whether there really is a sensible "null" version. As I wrote in my answer, providing dummy data can easily lead to hard-to-diagnose problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.