C#

What is NullReferenceException in C#?

In C#, a NullReferenceException occurs when we try to access a variable whose value has not been set or has been set to null. It can be easy to trigger this exception accidentally, so it’s important to be aware of how to avoid it in the first place. In this article, we’ll take a look at some common causes of NullReferenceException errors and how to fix them. We’ll also discuss ways to prevent NullReferenceException errors from happening in the first place.

To download the source code for this article, you can visit our GitHub repository.

Without further ado, let’s get started!

What Is a Null Object in C#?

In C#, a null object is an uninitialized object. This means that the object doesn’t have a value (other than null) assigned to it yet. When we create a new object, it’s automatically assigned a null value. We can change this by explicitly assigning a value to the object, but it will remain null until we do so.

Let’s understand what causes the NullReferenceException in C#. 

What Causes the NullReferenceException in C#?

As the name suggests, the NullReferenceException in C# occurs when we try accessing a null object.

Just like other object references, we can pass null values when we attempt to dereference them or pass them to other methods, which can make it difficult to debug and fix this exception. 

We can get the NullReferenceException thrown in various scenarios, which we’ll now look at.

Forgetting to Instantiate a Reference Type

Forgetting to instantiate a reference type is one of the most common causes of this exception:

public List<string> StudentList() 
{
    List<string> studentList = null;

    studentList.Add("John Doe");

    return studentList;
}

Here, we intend to return a List<string> containing a value “John Doe” to the user but the compiler throws a NullReferenceException when we attempt to run it. 

Next, we can verify that the compiler throws the NullReferenceException successfully:

[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void GivenAListObject_WhenNotInstantiated_VerifyThrowsNullReferenceException()
{
    var studentObj = new ExceptionMethods();

    var studentList = studentObj.StudentList();

    Assert.IsNull(studentList);
}

To fix that error, we simply need to instantiate the studentList object in the right way:

public List<string> FixedStudentList()
{
    var studentList = new List<string>();

    studentList.Add("John Doe");

    return studentList;
}

We can proceed to verify that the FixedStudentList() method works correctly by checking that it returns “John Doe” and is not null:

var studentObj = new ExceptionMethods();

var studentList = studentObj.FixedStudentList();
var student = "John Doe";

Assert.IsNotNull(studentList);
Assert.IsInstanceOfType(studentList, typeof(List<string>));
CollectionAssert.Contains(studentList, student);

Failing to Dimension Arrays Before Initializing Them

We have to dimension arrays before initializing them. Therefore, when we attempt to declare an array without specifying the number of elements it is going to hold, it will result in a NullReferenceException being thrown when we attempt to initialize its values.

Let’s simulate this scenario with an example:

public int[] RandomNumbers()
{
    var rand = new Random();

    int[] numbers = null;

    for (int i = 0; i < numbers.Length; i++) 
    {
        numbers[i] = rand.Next();
    }
 
    return numbers;
}

Here, we try to generate random numbers but we do not specify the number of elements while declaring the array, which throws the NullRefereceException:

[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void GivenAnArray_WhenNotInstantiated_VerifyThrowsNullReferenceException()
{
    var arrayObj = new ExceptionMethods();

    var randomNumbers = arrayObj.RandomNumbers();

    Assert.IsNull(randomNumbers);
}

To fix this error, we need to declare the number of elements before initializing the array:

public int[] FixedRandomNumbers()
{
    var rand = new Random();

    var numbers = new int[50];

    for (int i = 0; i < numbers.Length; i++)
    {
        numbers[i] = rand.Next();
    }

    return numbers;
}

Next, we can also go ahead to verify that the method runs successfully without any errors:

var arrayObj = new ExceptionMethods();

var randomNumbers = arrayObj.FixedRandomNumbers();

Assert.IsNotNull(randomNumbers);
Assert.IsInstanceOfType(randomNumbers, typeof(int[]));          

Assuming a Method Always Returns Non-null Values

As the title suggests, sometimes we may erroneously assume that a method is going to return non-null values. For example, a database table may contain some null values, which we have to account for when implementing our business logic.

Let’s implement a simple class to simulate this scenario:

public class Teacher
{
    public string? FirstName { get; set; }

    public Teacher()
    {
    }

    public Teacher[] AddRange(string[] firstNames)
    {
        var teachers = new Teacher[firstNames.Length];

        for (int i = 0; i < firstNames.Length; i++) 
        {
            teachers[i] = new Teacher(firstNames[i]);
        }
            
        return teachers;
    }

    public Teacher(string firstName)
    {
        this.FirstName = firstName;
    }
}

First, we define a property FirstName that must always have a non-null value when exiting the constructor. The AddRange method takes a string array and returns an object of the type Teacher[]

Next, we are going to implement a simple method to search for a single teacher from the Teacher[] array:

public string Teachers(string searchString)
{
    var personObj = new Teacher();
    
    var people = personObj.AddRange(new string[] { "John", "Mary", "Jane", "Usher", "Andrew", "Grace", "Aston", "Sheila" });
    var result = Array.Find(people, p => p.FirstName == searchString);

    return result.ToString();
}

The Teachers() method takes a string searchString as its sole parameter and uses the inbuilt Array.Find() method to search for it. Since FirstName is a non-nullable property, we are assuming that the method will always return a value.

We can verify that the Teachers method throws a NullReferenceException with this test:

[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void GivenAnArray_WhenSearching_VerifyThrowsNullReferenceException()
{
    var listObj = new ExceptionMethods();

    var searchPerson = listObj.Teachers("Steve");

    Assert.IsNull(searchPerson);
}

To address this problem, we need to ensure that we check for the method’s return value to make sure it is not null:

public string FixedTeachers(string searchString)
{
    var personObj = new Teacher();

    var people = personObj.AddRange(new string[] { "John", "Mary", "Jane", "Usher", "Andrew", "Grace", "Aston", "Sheila" });
    var result = Array.Find(people, p => p.FirstName == searchString);
    if (result != null)
    {
        return result.ToString();
    }
    else
    {
        return $"{searchString} could not be found";
    }
}

We can verify that our fix works by checking whether the FixedTeachers() method returns a string and is not null: 

var listObj = new ExceptionMethods();

var searchPerson = listObj.FixedTeachers("Steve");

Assert.IsNotNull(searchPerson);
Assert.IsInstanceOfType(searchPerson, typeof(string));

Enumerating Arrays Elements With Reference Types

In some cases, we may encounter the NullReferenceException when attempting to process array elements when some of them are null. Let’s try to simulate this scenario with an example:

public string[] CapitalizeNames() 
{
    var names = new string[] { "John", "Mary", null, null, "Andrew", "Grace", "Aston", "Sheila" };

    for (int i = 0; i < names.Length; i++)
    {
        names[i] = names[i].ToUpper();
    }

    return names;
}

The CapitalizeNames() method converts the string elements in the names array to upper-case using the inbuilt string.ToUpper() method. However, since some of the elements are null, attempting to convert them to uppercase throws the NullReferenceException, which we can verify:

[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void GivenAnArray_WhenSomeElementsNull_VerifyThrowsNullReferenceException()
{
    var arrayObj = new ExceptionMethods();
    
    var capitalizedNames = arrayObj.CapitalizeNames();
    
    Assert.IsNull(capitalizedNames);
}

To resolve this error, we need to check for null values before calling the string.ToUpper() method. We can make use of the string.Length property or the string.IsNullOrEmpty() method to check if a given array element is null:

public string[] FixedCapitalizeNames()
{
    var names = new string[] { "John", "Mary", null, null, "Andrew", "Grace", "Aston", "Sheila" };

    for(int i = 0; i < names.Length; i++)
    {
        if (!string.IsNullOrEmpty(names[i])) 
        {
            names[i] = names[i].ToUpper();
        }
    }

    return names;
}

We can then proceed to check that our method works without any issues with this test:

var arrayObj = new ExceptionMethods();

var capitalizedNames = arrayObj.FixedCapitalizeNames();

Assert.IsNotNull(capitalizedNames);
CollectionAssert.Contains(capitalizedNames, "JOHN");

Passing Null Arguments to Methods

We can trigger the exception when we attempt to pass null arguments to methods. Just like other reference types, we can pass null objects across different methods. Some methods may validate the arguments they receive and end up throwing the System.ArgumentNullException when they detect null arguments. On the other hand, when the methods fail to check for null arguments they end up throwing the NullReferenceException instead. 

Let’s simulate this scenario with an example:

public List<string> PopulateList(List<string> peopleNames) 
{
    var names = new string[] { "John", "Mary", "Andrew", "Grace", "Aston", "Sheila" };

    foreach (var person in names) 
    {
        peopleNames.Add(person);
    }
        
    return peopleNames;
}

The PopulateList() method takes a peopleNames list object and appends the array of elements in the names array to that list before returning it back to the user. Here, we are assuming that the PeopleList() method is going to always receive arguments that are not null. 

Let’s test what happens when we try to pass a null List<string> object to the PopulateList() method: 

[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public void GivenAMethod_WhenNullArgumentsPassed_VerifyThrowsNullReferenceException()
{
    var namesObj = new ExceptionMethods();

    List<string> currentPeople = null;
    var peopleList = namesObj.PopulateList(currentPeople);

    Assert.IsNull(peopleList);
}

Assuming that a method is going to always get non-null arguments is why we get the exception in this case. Therefore, just like in our other examples, we need to check for null arguments before appending items to the list. Besides that, we can use different exception handling techniques to deal with the exception as we invoke the PopulateList() method as we can see in this example:

public List<string> FixedPopulateList(List<string> peopleNames)
{
    var names = new string[] { "John", "Mary", "Andrew", "Grace", "Aston", "Sheila" };

    if (peopleNames == null) 
    {
        peopleNames = new List<string>();
    }

    foreach (var person in names) 
    {
        peopleNames.Add(person);
    }
        
    return peopleNames;
}

Here, we see that we check whether the list is null before attempting to append a list of names to it, which helps us avoid the NullReferenceException error. We can proceed to verify that the FixedPopulateList() method returns a List<string> object that is not null:

var namesObj = new ExceptionMethods();

List<string> currentPeople = null;
var peopleList = namesObj.FixedPopulateList(currentPeople);

Assert.IsNotNull(peopleList);
CollectionAssert.Contains(peopleList, "Mary");

How to Debug the NullReferenceException in C#?

There are different ways that we can use to find the source of a NullReferenceException in C#.

Generally, when using Visual Studio, we can use different debugging strategies to anticipate and fix syntax and logical errors. Although the compiler may show some warnings and show where the error is, one of the most common techniques that we can use is setting breakpoints strategically to anticipate any errors. 

We can also use unit tests to verify that such exceptions don’t occur before shipping out code to production. Finally, we can inspect variables and all their references to ensure that they have non-null references to avoid getting the NullReferenceException. 

How to Avoid Getting the NullReferenceExpection in C#?

To start with, we can avoid getting the NullReferenceException in C# by always checking for null values and ignoring them or replacing them with default values as we have done in our last example:

if (result != null)
{
    return result.ToString();
}
else
{
    return $"{searchString} could not be found";
}

Besides checking for null values, we can use exception handling techniques to ensure that our code does not trigger such exceptions during execution. Simple try-catch blocks or the use of custom exceptions can come in handy when debugging applications as they can help us isolate problematic code. 

On top of that, C# supports nullable types, which we can use in these situations. For example, we can define a nullable integer as int? number = null; which is the shortened version of  Nullable<int> number = null;. In this case, the question mark shows that the variable can hold  null in the variable number. We can then proceed to check whether number is null with if statements such as if (number.HasValue) or if (number == null)

To avoid getting the NullReferenceException at the project level, we can take advantage of nullable contexts. These contexts help us control how the compiler interprets reference types. To protect the project against the NullReferenceExecption, we can choose to enable it in the project’s csproj file as <Nullable>enable<Nullable>. To understand all the different options that we can use with nullable contexts, please refer to this article

Using the Null-Coalescing Operator

Finally, we can use the null-coalescing operator ?? as a way to avoid getting the NullReferenceException in C#. The null-coalescing operator is a binary operator that is used to assign a default value to a variable. The left-hand operand must be of a reference type, and the right-hand operand must be of the same type or convertible to the type of the left-hand operand. If the left-hand operand is not null, it is evaluated and returned; otherwise, the right-hand operand is evaluated and becomes the result of the operation.

Here is an example of how we can use the null-coalescing operator in C#:

int? num = null;
int result = num ?? 0; 

First, we assign the value null to the num variable. Next, we proceed to check if the value of num is not null, then result will be equal to num. On the other hand, if num is null, then result will be equal to 0. By using this operator, we can assign a default value to a variable if the variable is null, which helps us avoid a NullReferenceException.

These are useful ways to prevent errors in our code and make our code more robust.

Conclusion

In this article, we have learned the causes of NullReferenceException, debugging techniques, and how to avoid getting it as we code. We are eager to keep learning together, so, in case you think of some scenarios that can cause the NullReferenceExecption that are not in this article, please free to comment below and we’ll add them as soon as possible. 

Code Maze

Share
Published by
Code Maze

Recent Posts

Code Maze Weekly #149

Issue #149 of the Code Maze weekly. Check out what's new this week and enjoy…

Updated Date Nov 25, 2022

C# String Interpolation

Very early in the history of programming, we've seen the need to use text on…

Updated Date Nov 24, 2022

How to Check if a String Ends With a Number in C#

Checking if a string ends with a number in C# is a very common operation.…

Updated Date Nov 25, 2022

How to Execute Stored Procedures With EF Core 7

In this article, we will see how to use stored procedures in Entity Framework Core…

Updated Date Nov 22, 2022

HashSet vs SortedSet in C#

The HashSet<T> and SortedSet<T> classes in the System.Collections.Generic namespace define two ways of storing and iterating…

Updated Date Nov 22, 2022

Code Maze Weekly #148

Issue #148 of the Code Maze weekly. Check out what's new this week and enjoy…

Updated Date Nov 18, 2022