Condividi tramite


Troubleshooting Exceptions: System.NullReferenceException

A NullReferenceException occurs when you try to use a method or property of a reference type (C#, Visual Basic) whose value is null. For example, you may have tried to use an object without first using the new keyword (New in Visual Basic), or tried to use an object whose value was set to null (Nothing in Visual Basic).

Sections in this article

Classes used in this article

Common causes of NullReferenceExceptions

Finding the source of NullReferenceExceptions during development

Avoiding NullReferenceExceptions

Handling NullReferenceExceptions in release code

Classes used in this article

Most of the examples in this article use one or both of these classes:

public class Automobile
{
    public EngineInfo Engine {get; set;}
}

public class EngineInfo
{
    public EngineInfo() { }

    public EngineInfo(string powerSrc, double engineSize)
    {
        Power = powerSrc;
        Size = engineSize;
    }

    public double Size { get; set; }
    public string Power = null;
}
   
Public Class Automobile
    Public Property Engine As EngineInfo
End Class

Public Class EngineInfo
    Public Sub New()
    End Sub

    Public Sub New(powerSrc As String, engineSize As Double)
        Power = powerSrc
        Size = engineSize
    End Sub

    Public Property Size() As Double
    Public Power As String = Nothing
End Class

Back to topOther sections in this article

Common causes of NullReferenceExceptions

Any reference type variable can be null. Local variables, the properties of a class, method parameters, and method return values can all contain a null reference. Calling methods or properties of these variables when they are null causes a NullReferenceException. Specific cases:

A local variable or member field is declared but not initialized

A property or field is null

A method parameter is null

The return value of a method is null

An object in a collection or array is null

An object is not created because of a condition

An object passed by reference to a method is set to null

A local variable or member field is declared but not initialized

This simple error happens most frequently in Visual Basic code. Except in situations like declaring a variable to be passed as an out parameter, the C# compiler does not allow the use of a local reference variable unless it's initialized. The Visual Basic compiler generates a warning.

  • In the following C# code, the highlighted line generates this compiler error:

    Use of unassigned local variable 'engine'
  • In the Visual Basic code, the highlighted line generates compiler warning BC42104:

    Variable 'engine' is used before it has been assigned a value.
    
    

A null reference exception could result at runtime.

And the line does throw a NullReferenceException when it runs.
public void NullReferencFromUninitializedLocalVariable()
{
    EngineInfo engine;
    Console.WriteLine(engine.ToString());
}
Public Sub NullReferencFromUninitializedLocalVariable()
    Dim engine As EngineInfo
    Console.WriteLine(engine.ToString())
End Sub

Back to topEntries in this section

Back to topSections in this article

A property or field is null

The fields and properties of a class are automatically initialized to their default value when the class is created. The default value of a reference type is null (Nothing in Visual Basic) Calling member methods on a field or property of a parent class when the field or property value is null causes a NullReferenceException.

In this example, the highlighted line throws a NullReferenceException because the Engine property of car is auto-initialized to null.

public void NullReferenceFromProperty()
{
    var car = new Automobile();

    Console.WriteLine(car.Engine.ToString());
}
Public Sub NullReferenceFromProperty()
    Dim car = New Automobile()
    Console.WriteLine(car.Engine.ToString())
End Sub

Back to topEntries in this section

Back to topSections in this article

A method parameter is null

A method parameter that is a reference type can be null (Nothing in Visual Basic). Calling member methods or properties on a parameter value that is null causes a NullReferenceException.

In this example, the highlighted line throws a NullReferenceException because BadEngineInfoPassedToMethod calls NullReferenceFromMethodParameter with a parameter that is null.

public void BadEngineInfoPassedToMethod()
{
    EngineInfo eng = null;
    NullReferenceFromMethodParameter(eng);
}

public void NullReferenceFromMethodParameter(EngineInfo engine)
{
    Console.WriteLine(engine.ToString());
}
Public Sub BadParameterPassedToMethod() As EngineInfo
    Dim eng As EngineInfo = Nothing
    NullReferenceFromMethodParameter(eng)
End Sub

Public Sub NullReferenceFromMethodParameter(engine As EngineInfo)
    Console.WriteLine(engine.ToString())
End Sub

Back to topEntries in this section

Back to topSections in this article

The return value of a method is null

A method that returns a reference type can return null (Nothing in Visual Basic). Calling methods or properties of the returned reference type causes a NullReferenceException when the reference is null.

In this example, the highlighted line throws a NullReferenceException because the call to BadGetEngineInfo returns a null reference in the NullReferenceFromMethodParameter method.

public EngineInfo BadGetEngineInfo()
{
    EngineInfo engine = null;
    return engine;
}

public void NullReferenceFromMethodReturnValue()
{
    var engine = BadGetEngineInfo();
    Console.WriteLine(engine.ToString());
}
Public Function BadGetEngineInfo() As EngineInfo
    Dim engine As EngineInfo = Nothing
    Return engine
End Function

Public Sub NullReferenceFromMethodReturnValue()
    Dim engine = BadGetEngineInfo()
    Console.WriteLine(engine.ToString())
End Sub

Back to topEntries in this section

Back to topSections in this article

An object in a collection or array is null

A list or array of reference types can contain an item that is null. Calling methods or properties of a list item that is null causes a NullReferenceException.

In this example, the highlighted line in NullReferenceFromListItem() throws a NullReferenceException because the call to BadGetCarList returns an item that is null.

public Automobile[] BadGetCarList()
{
    var autos = new Automobile[10];
    for (int i = 0; i autos.Length; i++)
    {
        if (i != 6)
        {
            autos[i] = new Automobile();
        }
    }
    return autos;
}

public void NullReferenceFromListItem()
{
    var cars = BadGetCarList();
    foreach (Automobile car in cars)
    {
        Console.WriteLine(car.ToString());
    }
}
Public Function BadGetCarList() As Automobile()
    Dim autos = New Automobile(10) {}
    For i As Integer = 0 To 9
        If i <> 6 Then
            autos(i) = New Automobile()
        End If
    Next
    Return autos
End Function

Public Sub NullReferenceFromListItem()
    Dim cars = BadGetCarList()
    For Each car As Automobile In cars
        Console.WriteLine(car.ToString())
    Next
End Sub

Back to topEntries in this section

Back to topSections in this article

An object is not created because of a condition

If a reference type is initialized in a conditional block, the object is not created when the condition is false.

In this example the highlighted line in NullReferenceFromConditionalCreation throws a NullReferenceException because it initializes the engine variable only if the DetermineTheCondition() method returns true.

 public bool DetermineTheCondition()
{
    return false;
}

public void NullReferenceFromConditionalCreation()
{
    EngineInfo engine = null;
    var condition = DetermineTheCondition();
    if (condition)
    {
        engine = new EngineInfo();
        engine.Power = "Diesel";
        engine.Size = 2.4;
    }
    Console.WriteLine(engine.Size);
}
Public Function DetermineTheCondition() As Boolean
    Return False
End Function

Public Sub NullReferenceFromConditionalCreation()
    Dim engine As EngineInfo = Nothing
    Dim condition = DetermineTheCondition()
    If condition Then
        engine = New EngineInfo()
        engine.Power = "Diesel"
        engine.Size = 2.4
    End If
    Console.WriteLine(engine.Size)
End Sub

Back to topEntries in this section

Back to topSections in this article

The property of an object passed to a method is set to null

When an object is passed as a parameter to a method by value (without use of the ref or out keyword in C# or the ByRef keyword in Visual Basic), the method can't change the memory location of the parameter—what the parameter points to—but it can change the properties of the object.

In this example, the NullPropertyReferenceFromPassToMethod method creates an Automobile object and initializes the Engine property. It then calls BadSwapCarEngine, passing the new object as the parameter. BadSwapCarEngine sets the Engine property to null, which causes the highlighted line in NullPropertyReferenceFromPassToMethod to throw a NullReferenceException.

public void BadSwapCarEngine(Automobile car)
{
    car.Engine = null;
}

public void (Automobile car)
{
    car.Engine = new EngineInfo("GAS", 1.5);
    BadSwapCarEngine(car);
    Console.WriteLine(car.Engine.ToString());
}
Public Sub BadSwapCarEngine(car As Automobile)
    car.Engine = Nothing
End Sub

Public Sub NullPropertyReferenceFromPassToMethod()
    Dim car As New Automobile()
    car.Engine = New EngineInfo("GAS", 1.5)
    BadSwapCarEngine(car)
    Console.WriteLine(car.Engine.ToString())
End Sub

Back to topEntries in this section

Back to topSections in this article

An object passed by reference to a method is set to null

When you pass a reference type as a parameter to a method by reference (using the ref or out keyword in C# or the ByRef keyword in Visual Basic), you can change the memory location that the parameter points to.

If you pass a reference type by reference to a method, the method can set the referenced type to null (Nothing in Visual Basic).

In this example, the highlighted line in NullReferenceFromPassToMethodByRef throws a NullReferenceException because the call to the BadEngineSwapByRef method sets the stockEngine variable to null.

public void BadEngineSwapByRef(ref EngineInfo engine)
{
    engine = null;
}

public void NullReferenceFromPassToMethodByRef()
{
    var stockEngine = new EngineInfo();
    stockEngine.Power = "Gas";
    stockEngine.Size = 7.0;
    BadSwapEngineByRef(ref stockEngine);
    Console.WriteLine(stockEngine.ToString());
}
Public Sub BadSwapEngineByRef(ByRef engine As EngineInfo)
    engine = Nothing
End Sub

Public Sub NullReferenceFromPassToMethodByRef()
    Dim formatStr = "The stock engine has been replaced by a {0} liter {} engine"
    Dim stockEngine = New EngineInfo()
    stockEngine.Power = "Gas"
    stockEngine.Size = 7.0
    BadSwapEngineByRef(stockEngine)
    Console.WriteLine(stockEngine.ToString())
End Sub

Back to topEntries in this section

Back to topSections in this article

Finding the source of a null reference exception during development

Use data tips, the Locals window, and watch windows to see variables values

Walk the call stack to find where a reference variable is not initialized or set to null

Set conditional breakpoints to stop debugging when an object is null (Nothing in Visual Basic)

Use data tips, the Locals window, and watch windows to see variables values

  • Rest the pointer on the variable name to see its value in a data tip. If the variable references an object or a collection, you can expand the data type to examine its properties or elements.

  • Open the Locals window to examine the variables that are active in the current context.

  • Use a watch window to focus on how a variable changes as you step through the code.

Back to topEntries in this section

Back to topSections in this article

Walk the call stack to find where a reference variable is not initialized or set to null

The Visual Studio Call Stack window displays a list of the names of methods that have not completed when the debugger stops at an exception or breakpoint. You can select a name in the Call Stack window and choose Switch to frame to change the execution context to the method and examine its variables.

Back to topEntries in this section

Back to topSections in this article

Set conditional breakpoints to stop debugging when an object is null (Nothing in Visual Basic)

You can set a conditional breakpoint to break when a variable is null. Conditional breakpoints can be helpful when the null reference does not occur often—for example, when an item in a collection is null only intermittently. Another advantage of conditional breakpoints is that they enable you to debug an issue before you commit to a particular handling routine.

Back to topEntries in this section

Back to topSections in this article

Avoiding NullReferenceExceptions

Use Debug.Assert to confirm an invariant

Fully initialize reference types

Use Debug.Assert to confirm an invariant

An invariant is a condition that you are sure is true. A Debug.Assert (System.Diagnostics) statement is called only from debug builds of your apps and is not called from release code. If the invariant condition is not true, the debugger breaks at the Assert statement and displays a dialog box. Debug.Assert provides a check that the condition has not changed while you are developing the app. An assertion also documents for others who read your code that the condition must always be true.

For example, the MakeEngineFaster method assumes that its engine parameter will never be null because its only caller method (TheOnlyCallerOfMakeEngineFaster) is known to fully initialize the EngineInfo. The assert in MakeEngineFaster documents the assumption and provides a check that the assumption is true.

If someone adds a new caller method (BadNewCallerOfMakeEngineFaster) that does not initialize the parameter, the assert is triggered.

private void TheOnlyCallerOfMakeEngineFaster()
{
    var engine = new EngineInfo();
    engine.Power = "GAS";
    engine.Size = 1.5;
    MakeEngineFaster(engine);
}

private void MakeEngineFaster(EngineInfo engine)
{
    System.Diagnostics.Debug.Assert(engine != null, "Assert: engine != null");
    engine.Size *= 2;
    Console.WriteLine("The engine is twice as fast");
}

private void BadNewCallerOfMakeEngineFaster()
{
    EngineInfo engine = null;
    MakeEngineFaster(engine);
}
Public Sub TheOnlyCallerOfMakeEngineFaster()
    Dim engine As New EngineInfo
    engine.Power = "GAS"
    engine.Size = 1.5
    MakeEngineFaster(engine)
End Sub

Private Sub MakeEngineFaster(engine As EngineInfo)
    System.Diagnostics.Debug.Assert(engine IsNot Nothing, "Assert: engine IsNot Nothing")
    engine.Size = engine.Size * 2
    Console.WriteLine("The engine is twice as fast")
End Sub

Public Sub BadNewCallerOfMakeEngineFaster()
    Dim engine As EngineInfo = Nothing
    MakeEngineFaster(engine)
End Sub

Back to topEntries in this section

Back to topSections in this article

Fully initialize reference types

To avoid many NullReferenceExceptions, fully initialize reference types as close to their creation as possible.

Add full initialization to your own classes

If you control the class that throws a NullReferenceException, consider fully initializing the object in the type’s constructor. For example, here’s a revised version of the example classes that guarantees full initialization:

public class Automobile
{
    public EngineInfo Engine { get; set; }

    public Automobile() 
    { 
        this.Engine = new EngineInfo(); 
    }

    public Automobile(string powerSrc, double engineSize)
    {
        this.Engine = new EngineInfo(powerSrc, engineSize);
    }
}


public class EngineInfo
{
    public double Size {get; set;}
    public string Power {get; set;}

    public EngineInfo() 
    { 
        // the base engine 
        this.Power = "GAS"; 
        this.Size = 1.5; 
    }

    public EngineInfo(string powerSrc, double engineSize)
    {
        this.Power = powerSrc;
        this.Size = engineSize;
    }
}
Public Class Automobile
    Public Property Engine As EngineInfo

    Public Sub New() 
        Me.Engine = New EngineInfo() 
    End Sub 

    Public Sub New(powerSrc As String, engineSize As Double) 
        Me.Engine = New EngineInfo(powerSrc, engineSize) 
    End Sub

End Class

Public Class BaseEngineInfo
    Public Sub New() 
        ' the base engine 
        Me.Power = "GAS" 
        Me.Size = 1.5 
    End Sub

    Public Sub New(powerSrc As String, engineSize As Double)
        Power = powerSrc
        Size = engineSize
    End Sub

    Public Property Size() As Double
    Public Power As String = String.Empty
End Class

Note

Use lazy initialization for large or infrequently used properties

To reduce the memory footprint of your class and to increase its performance, consider using lazy initialization of reference-type properties. See Lazy Initialization.

Handling NullReferenceExceptions in release code

Check for null (Nothing in Visual Basic) before using a reference type

Use try – catch – finally (Try – Catch – Finally in Visual Basic) to handle the exception

It's better to avoid a NullReferenceException than to handle it after it occurs. Handling an exception can make your code harder to maintain and understand, and can sometimes introduce other bugs. A NullReferenceException is often a non-recoverable error. In these cases, letting the exception stop the app might be the best alternative.

However, there are many situations where handling the error can be useful:

  • Your app can ignore objects that are null. For example, if your app retrieves and processes records in a database, you might be able to ignore some number of bad records that result in null objects. Recording the bad data in a log file or in the application UI might be all you have to do.

  • You can recover from the exception. For example, a call to a web service that returns a reference type might return null if the connection is lost or the connection times out. You can attempt to reestablish the connection and try the call again.

  • You can restore the state of your app to a valid state. For example, you might be performing a multi-step task that requires you to save information to a data store before you call a method that throws a NullReferenceException. If the uninitialized object would corrupt the data record, you can remove the previous data before you close the app.

  • You want to report the exception. For example, if the error was caused by a mistake from the user of your app, you can generate a message to help him supply the correct information. You can also log information about the error to help you fix the problem. Some frameworks, like ASP.NET, have a high-level exception handler that captures all errors to that the app never crashes; in that case, logging the exception might be the only way you can know that it occurs.

Here are two ways to handle NullReferenceException in release code.

Check for null (Nothing in Visual Basic) before you use a reference type

Using an explicit test for null before you use an object avoids the performance penalty of try-catch-finally constructs. However, you still have to determine and implement what to do in response to the uninitialized object.

In this example, the CheckForNullReferenceFromMethodReturnValue tests the return value of the BadGetEngineInfo method. If the object is not null, it is used; otherwise, the method reports the error.

public EngineInfo BadGetEngineInfo()
{
    EngineInfo engine = null;
    return engine;
}

public void CheckForNullReferenceFromMethodReturnValue()
{
    var engine = BadGetEngineInfo();
    if(engine != null)
    {
        // modify the info
        engine.Power = "DIESEL";
        engine.Size = 2.4;
    }
    else
    {
        // report the error
        Console.WriteLine("BadGetEngine returned null")
    }
}
public EngineInfo BadGetEngineInfo()
{
    EngineInfo engine = null;
    return engine;
}
Public Sub CheckForNullReferenceFromMethodReturnValue()
    Dim engine = BadGetEngineInfo()
    If (engine IsNot Nothing) Then
        ' modify the info
        engine.Power = "DIESEL"
        engine.Size = 2.4
    Else
        ' report the error
        Console.WriteLine("BadGetEngineInfo returned Nothing")
    End If

End Sub

Back to topEntries in this section

Back to topSections in this article

Use try-catch-finally (Try-Catch-Finally in Visual Basic) to handle the exception

Using the built-in exception handling constructs (try, catch, finally in C#, Try, Catch, Finally in Visual Basic) offers more options for dealing with NullReferenceExceptions than checking whether an object is not null.

In this example, CatchNullReferenceFromMethodCall uses two asserts to confirm the assumption that its parameter contains a complete automobile, including an engine. In the try block, the highlighted line throws a NullReferenceException because the call to RarelyBadEngineSwap can destroy the car's Engine property. The catch block captures the exception, writes the exception information to a file, and reports the error to the user. In the finally block, the method insures that the state of the car is no worse than when the method began.

public void RarelyBadSwapCarEngine(Automobile car)
{
    if ((new Random()).Next() == 42)
    {
        car.Engine = null;
    }
    else
    {
        car.Engine = new EngineInfo("DIESEL", 2.4);
    }
}

public void CatchNullReferenceFromMethodCall(Automobile car)
{
    System.Diagnostics.Debug.Assert(car != null, "Assert: car != null");
    System.Diagnostics.Debug.Assert(car.Engine != null, "Assert: car.Engine != null");

    // save current engine properties in case they're needed
    var enginePowerBefore = car.Engine.Power;
    var engineSizeBefore = car.Engine.Size;

    try
    {
        RarelyBadSwapCarEngine(car);
        var msg = "Swap succeeded. New engine power source: {0} size {1}";
        Console.WriteLine(msg, car.Engine.Power, car.Engine.Size);
    }
    catch(NullReferenceException nullRefEx)
    {
        // write exception info to log file
        LogException(nullRefEx);
        // notify the user
        Console.WriteLine("Engine swap failed. Please call your customer rep.");
    }
    finally
    {
        if(car.Engine == null)
        {
            car.Engine = new EngineInfo(enginePowerBefore, engineSizeBefore);
        }
    }
}
Public Sub RarelyBadSwapCarEngine(car As Automobile)
    If (New Random()).Next = 42 Then
        car.Engine = Nothing
    Else
        car.Engine = New EngineInfo("DIESEL", 2.4)
    End If
End Sub

Public Sub CatchNullReferenceFromMethodCall(car As Automobile)
    System.Diagnostics.Debug.Assert(car IsNot Nothing)
    System.Diagnostics.Debug.Assert(car.Engine IsNot Nothing)

    ' save current engine properties in case they're needed
    Dim powerBefore = car.Engine.Power
    Dim sizeBefore = car.Engine.Size

    Try
        RarelyBadSwapCarEngine(car)
        Dim msg = "Swap succeeded. New engine power source: {0} size {1}"
        Console.WriteLine(msg, car.Engine.Power, car.Engine.Size)
    Catch nullRefEx As NullReferenceException
        ' write exception info to log file
        LogException(nullRefEx)
        ' notify user
        Console.WriteLine("Engine swap failed. Please call your customer rep.")
    Finally
        If car.Engine Is Nothing Then car.Engine = New EngineInfo(powerBefore, sizeBefore)
    End Try

End Sub

Back to topEntries in this section

Back to topSections in this article

Design Guidelines for Exceptions (.NET Framework Design Guidelines)

Handling and Throwing Exceptions (.NET Framework Application Essentials)

How to: Receive First-Chance Exception Notifications (.NET Framework Development Guide)

How to: Handle Exceptions in a PLINQ Query (.NET Framework Development Guide)

Exceptions in Managed Threads (.NET Framework Development Guide)

Exceptions and Exception Handling (C# Programming Guide)

Exception Handling Statements (C# Reference)

Try...Catch...Finally Statement (Visual Basic)

Exception Handling (F#)

Exceptions in C++/CLI

Exception Handling (Task Parallel Library)

Exception Handling (Debugging)

Walkthrough: Handling a Concurrency Exception (Accessing Data in Visual Studio)

How to: Handle Errors and Exceptions that Occur with Databinding (Windows Forms)

Handling exceptions in network apps (XAML) (Windows)

Back to topSections in this article