One of the most frequent problems that a new C# programmer encounters when testing an application is a null reference exception. This is a runtime error caused when a programmer has forgotten to initialize a reference, but then tries to access it as though it were referencing an actual object.
Let's purposely create a situation where a null reference exception will arise. We'll use the following simplified version of the Section class in our experiment that only declares two fields, representing a section number and an instructor:
using System; public class Section { private int sectionNo; private Professor instructor; // etc. // Constructor. public Section(int sNo) { this.SectionNo = sNo; // A specific Professor has not yet been identified to teach this Section; // the client application must explicitly call the Instructor property as // a separate step later on, to initialize the instructor field. So, by // default, the instructor field is initialized to the value null. } //----------------- // Properties. //----------------- public int SectionNo { get { return sectionNo; } set { sectionNo = value; } } public Professor Instructor { get { return instructor; } set { instructor = value; } } public void Display() { // This method is written assuming that both the sectionNo and // instructor have already been initialized to meaningful values. Console.WriteLine("\tSection No.: " + this.SectionNo); Console.WriteLine("\tProfessor: " + this.Instructor.Name); } }
Now, in our main program, we'll try to instantiate, and then display, a Section object:
using System; public class NullReferenceExample { static void Main(string[] args) { Section s = new Section(1); // We've forgotten to set s's Instructor property to refer to // a valid Professor object, so when we call s's Display // method on the next line, we'll be in trouble at run time! s.Display(); } }
We get the following output from our program, including a runtime error message generated by our call to s.Display():
Section No: 1 System.NullReferenceException: Object reference not set to an instance of an object at Section.Display() at NullReferenceExample.Main(String[] args)
This runtime output is known as an exception trace—it indicates that an exception occurred in the Display method of the Section class, which was in turn called from the Main method of the NullReferenceExample class.
If we want to know precisely which line of source code the exception occurred on, we can include the line numbers in an exception trace. To do so, the program must be recompiled with the debugging option turned on:
csc /debug NullReferenceExample.cs Section.cs
in which case the exception trace would display line numbers as follows:
Section No: 1 System.NullReferenceException: Object reference not set to an instance of an object at Section.Display() in C:\Section.cs : line 24 at NullReferenceExample.Main(String[] args) in C:\NullReferenceExample.cs : line 8
A null reference exception indicates that some reference variable, instead of referring to a legitimate object, refers to nothing! That is, that the value of the reference variable in question was null at the time that the offending line of code was executed. In this case, the exception actually arises in the line of code in the Display method that is highlighted here:
public void Display() { Console.WriteLine("\tSection No.: " + this.SectionNo); Console.WriteLine("\tProfessor: " + this.Instructor.Name); }
In this line of code, the Instructor property's get accessor—this.Instructor— is returning the value of the instructor field of the Section object, which was initialized to the value null by the constructor and then never updated. So, the subsequent attempt to invoke the Name property—this.Instructor.Name—is what actually raised the exception—we can't get the name of a nonexistent object! We are, in effect, trying to evaluate the expression null.Name, which makes no sense.
If it's likely that we'll want to display information about a Section object that doesn't have a Professor assigned to teach it, we could "bulletproof" the offending line of code to read as follows:
public void Display() { Console.WriteLine("\tSection No.: " + this.SectionNo); Professor p = this.Instructor; if (p != null) Console.WriteLine("\tProfessor: " + p.Name); }
Here, we've inserted a test to ensure that p isn't equal to null before we attempt to "talk" to the object referenced by p. If p is indeed null, the second WriteLine call is skipped over. We could be a bit more thorough, adding an else clause to our if statement so that two lines of output are always generated no matter what:
public void Display() { Console.WriteLine("\tSection No.: " + this.SectionNo); Professor p = this.Instructor; if (p != null) { Console.WriteLine("\tProfessor: " + p.Name); } else { Console.WriteLine("\tProfessor: TBD"); } }