NullReferenceException について

初級者向けにおさらいします。

目次

この例外エラーの説明

Null Reference(参照しようとした変数が null 状態、つまり Nothing 状態(準備できていない状態)なのに使おうとアクセスすることで発生する)Exception です。

事例とその対処方法

例外エラーは、想定外の扱われ方をすると発生して飛んで来ます。それは命令の使い方が間違っていたり、存在しないデータを扱おうとしていたり、アカウント権限を越えたアクセスをしようとしていたり(Windows 側やウェブ側の話だったり)、サービスが動いていないのに連携しようとしたり、製品上の仕様考慮モレだったり、そういう系です。

こうなっている前提のはずだから、こうやろうとしたのに、実際はここがこうなっているからダメじゃん!こういう場合の処理が無いじゃん!みたいなコードになっていませんか?

クラス型データ全般

実際には、以下のような使い方はあまりないかと思います。

Class Class1
    Public Number As Integer = 0
End Class

Module Module1

    Sub Main()

        Dim obj As Class1 = Nothing
        Dim number As Integer = obj.Number


        Console.ReadKey()
    End Sub

End Module
System.NullReferenceException: 'オブジェクト参照がオブジェクト インスタンスに設定されていません。'

obj が Nothing でした。

以下のように、メソッドに渡した引数がインスタンス生成されていなかった、またはそのメンバーがインスタンス生成されていなかった、というケースの方が多いかもしれません。

Sub Main()

    Dim obj As Class1 = Nothing
    Work(obj)


    Console.ReadKey()
End Sub

Sub Work(obj As Class1)

    Dim number As Integer = obj.Number

End Sub

対策としては、事前にインスタンスチェックすることですが、できるだけインスタンスチェックしなくてもインスタンス生成されていることが保証できるような書き方を目指した方が良い気がします。

Sub Work(obj As Class1)

    ' 1
    If obj IsNot Nothing Then
        Dim number As Integer = obj.Number
    End If

    ' 2
    Dim number2 As Integer? = obj?.Number
    ' obj is Nothing -> number2 = Nothing
    '                -> number2 = Integer Value

    If number2.HasValue Then

    End If

    ' 3
    Dim number3 As Integer = If(obj Is Nothing, 0, obj.Number)


End Sub

例えば、限定的であまり良い例ではないですが、インスタンス生成してから渡している場合、あえて Work メソッド内でインスタンスチェックする必要はないと思います。

Sub Main()

    Dim obj As Class1 = New Class1
    Work(obj)


    Console.ReadKey()
End Sub

Private Sub Work(obj As Class1)

    Dim number As Integer = obj.Number

End Sub

あとは、できるだけクラス型データの場合は、デフォルトで宣言と同時に初期化(インスタンス生成)しておくことです。