読者です 読者をやめる 読者になる 読者になる

VBでDateTime型にNothingがセットできる理由

VB .NET

DateTimeは値型である。本来はnull/Nothingはセットできないと思っていた。
でも、VBの場合Nothingがセットできてしまう。デフォルト値はNothingを示す。
なんでだろう?

下の書き込みに答えが載っていた。

GotDotNet Japan 掲示板 スレッド: DateTime型の引数をOptionalにする際の初期値

(Lady.BUGさんの書き込みより)

> DateTime型のデフォルト値は、 = Nohting みたいです。

これはちょっと違いますね、CType(Nothing, 構造体) が未初期化の構造体を返すためです。
.NET では確保されたインスタンスメンバは 0/False/Nothing で初期化されているため、 CType(Nothing, DateTime) が New DateTime(0) と同じ結果にみえているから、と。

NothingをDateTime型と比較しようとすると、CType(Nothing, DateTime)が実行され、未初期化の構造体を返す。未初期化の構造体の中身はNew DateTime(0)である。
これが内部で行われているため、デフォルト値がNothingと等しくなるってことかな?


検証になるかわからないけど、色々初期化方法を試してみた。全て同じ結果を示す。
また、オブジェクトも全て等しいようだ。

Module DateInitializeTest

    Sub Main()
        Dim d1 As DateTime = New DateTime(0)
        Dim d2 As DateTime = Nothing
        Dim d3 As DateTime = CType(Nothing, DateTime)
        Dim d4 As DateTime
        Console.WriteLine("d1 = " + d1.ToString())
        Console.WriteLine("d2 = " + d2.ToString())
        Console.WriteLine("d3 = " + d3.ToString())
        Console.WriteLine("d4 = " + d4.ToString())
        Console.WriteLine("d1 = d2? " + d1.Equals(d2).ToString())
        Console.WriteLine("d1 = d3? " + d1.Equals(d3).ToString())
        Console.WriteLine("d2 = d3? " + d2.Equals(d3).ToString())
        Console.WriteLine("d1 = d4? " + d1.Equals(d4).ToString())
        Console.WriteLine("d4 = Nothing? " + d4.Equals(Nothing).ToString())
        Console.ReadLine()
    End Sub

End Module
結果
d1 = 0001/01/01 0:00:00
d2 = 0001/01/01 0:00:00
d3 = 0001/01/01 0:00:00
d4 = 0001/01/01 0:00:00
d1 = d2? True
d1 = d3? True
d2 = d3? True
d1 = d4? True
d4 = Nothing? True

だから値型でもNothingがセットできるのね。
ちなみにC#だとnullで初期化はできないし、DateTime型への変換もできない。

using System;

namespace DateTimeInitializeCS
{
    class DateTimeInitializeTest
    {
        static void Main(string[] args)
        {
            DateTime d1 = new DateTime(0);
            DateTime d2 = DateTime.Parse("0001/01/01");
            Console.WriteLine("d1 = " + d1.ToString());
            Console.WriteLine("d2 = " + d2.ToString());
            Console.WriteLine("d1 = d2? " + d1.Equals(d2).ToString());
            Console.ReadLine();
        }
    }
}

以上、C#の場合の初期化方法。

DateTime d3 = null;

とかやるとものすごい勢いで怒られます。

こういうのを意識させないVBは、すごいんだか、怖いんだか・・・