Nothing と null 状態
Nothing は C# でいう null であるという認識だと思いますが、Nothing キーワードとしての Nothing と、とある変数が、インスタンスが生成されているのかいないのか、つまり現在のインスタンスの状態としての Nothing 状態についておさらいしたいと思います。ポイントは構造体(値型)の場合と、クラス(参照型)の場合で振る舞いが違うことです。
目次
Class と Nothing
これが一番分かりやすい動きですが、クラス型の変数に Nothing が入っている場合、インスタンス生成されておらず、操作しようとすると NullReferenceException が発生してしまいます。
Class Class1 Public Number As Integer = 0 End Class Module Module1 Sub Main() Dim obj As Class1 = Nothing Dim result = obj.Number Console.ReadKey() End Sub End Module
出力結果
System.NullReferenceException: 'オブジェクト参照がオブジェクト インスタンスに設定されていません。' obj が Nothing でした。
必ずメンバーアクセスする前に、インスタンス生成するか、Nothing チェックしないといけないね、と分かります。
Structure と Nothing
続いて構造体の場合です。インスタンス生成していませんが、構造体の場合、宣言と同時に暗黙的にインスタンス生成されます。よって以下のように明示的にインスタンス生成しないで使うことができます(個人的には気持ち悪いので、明示的にインスタンス生成したいです)。
Structure Structure1 Public Number As Integer End Structure Module Module1 Sub Main() Dim obj As Structure1 Console.WriteLine(obj.Number) Console.ReadKey() End Sub End Module
出力結果
0
また、Structure に対して Nothing をセットすると、各 Structure 毎の規定値がセットされます。私たちが自前で作るような Structure の規定値はインスタンス生成です。同じ Structure でも、プリミティブ型の Structure である、Integer, Boolean, Date などは、それぞれ、0, False, Date.MinValue となります。
自前作成の構造体の場合、以下のように書いてもインスタンス生成されたものとして動作します。ただし混乱の元でしかないので、Dim obj As New Structure1
と書いた方が健康でいられる気がします。
Structure Structure1 Public Number As Integer End Structure Module Module1 Sub Main() Dim obj As Structure1 = Nothing Console.WriteLine(obj.Number) Console.ReadKey() End Sub End Module
出力結果
0
こちらはプリミティブ型の場合。
Module Module1 Sub Main() Dim i1 As Integer = Nothing Dim s1 As String = Nothing Dim b1 As Boolean = Nothing Dim d1 As Date = Nothing If i1 = Nothing Then Console.WriteLine("i1 は、Nothing でした") If s1 = Nothing Then Console.WriteLine("s1 は、Nothing でした1") If s1 Is Nothing Then Console.WriteLine("s1 は、Nothing でした2") If b1 = Nothing Then Console.WriteLine("b1 は、Nothing でした") If d1 = Nothing Then Console.WriteLine("d1 は、Nothing でした") Console.WriteLine("") i1 = 0 s1 = "" b1 = False d1 = Date.MinValue If i1 = Nothing Then Console.WriteLine("i1 は、Nothing でした") If s1 = Nothing Then Console.WriteLine("s1 は、Nothing でした1") If s1 Is Nothing Then Console.WriteLine("s1 は、Nothing でした2") If b1 = Nothing Then Console.WriteLine("b1 は、Nothing でした") If d1 = Nothing Then Console.WriteLine("d1 は、Nothing でした") Console.ReadKey() End Sub End Module
出力結果
i1 は、Nothing でした s1 は、Nothing でした1 s1 は、Nothing でした2 b1 は、Nothing でした d1 は、Nothing でした i1 は、Nothing でした s1 は、Nothing でした1 b1 は、Nothing でした d1 は、Nothing でした
Structure である Integer, Boolean, Date はそれぞれ規定値が、0, False, Date.MinValue ですので Nothing をセットすると各規定値がセットされます。つまり Structure では Nothing と規定値は同等であり、null 状態という意味ではありません。
一方で Class である String ですが、クラスなので Nothing をセットすると null 状態という意味の方になります。なのですが、プリミティブ型として振舞いたいため、規定値である空文字と Nothing を同等とみなす動きをします。
Module Module1 Sub Main() If "" = Nothing Then Console.WriteLine("True") End If If "" Is Nothing Then Console.WriteLine("True") Else Console.WriteLine("False") End If Console.ReadKey() End Sub End Module
出力結果
True False
空文字と Nothing が同じであるかどうかを =
で比較している場合はプリミティブ型として考えるので、規定値は空文字なので True と扱われます。しかし、Is
で比較する場合は、クラスとしてインスタンス生成してあるかどうかを見るので False という結果になります。String クラスとしては、空文字はインスタンス生成後の値ということですね。
まとまると
- クラスに対する Nothing は、インスタンス生成しているのか、していないのか(null 状態なのか)
- 構造体に対する Nothing は、null 状態なのかどうか
ではなく
各 Structure に合った規定値かどうか
くらいに場合分けで覚えておいた方が良いのではないかと思います。
頭が痛くなってきた
申し訳ないです。皆さんを困らせるために書いたのではないのです。知れば知るほど知りたくなかったというのも、まぁ通る道なのかなと思ったり。