有趣的“Nullable”

众所周知,Nullable是允许对一些值类型的数据类型直接赋值Null(VB.NET中为Nothing)的特殊值类型。如果你反编译这个值类型,将会看到这样一个局面——

[C#]

public struct Nullable<T> where T: struct

{

    private bool hasValue;

    internal T value;

    public Nullable(T value)

    {

        this.value = value;

        this.hasValue = true;

    }



    public bool HasValue

    {

        get

        {

            return this.hasValue;

        }

    }

    public T Value

    {

        get

        {

            if (!this.HasValue)

            {

                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);

            }

            return this.value;

        }

    }

    public T GetValueOrDefault()

    {

        return this.value;

    }



    public T GetValueOrDefault(T defaultValue)

    {

        if (!this.HasValue)

        {

            return defaultValue;

        }

        return this.value;

    }



    public override bool Equals(object other)

    {

        if (!this.HasValue)

        {

            return (other == null);

        }

        if (other == null)

        {

            return false;

        }

        return this.value.Equals(other);

    }



    public override int GetHashCode()

    {

        if (!this.HasValue)

        {

            return 0;

        }

        return this.value.GetHashCode();

    }



    public override string ToString()

    {

        if (!this.HasValue)

        {

            return "";

        }

        return this.value.ToString();

    }



    public static implicit operator T?(T value)

    {

        return new T?(value);

    }



    public static explicit operator T(T? value)

    {

        return value.Value;

    }

}

[VB.NET]

<Serializable, StructLayout(LayoutKind.Sequential), TypeDependency("System.Collections.Generic.NullableEqualityComparer`1"), TypeDependency("System.Collections.Generic.NullableComparer`1")> _

Public Structure Nullable(Of T As Structure)

    Private hasValue As Boolean

    Friend value As T

    Public Sub New(ByVal value As T)

        Me.value = value

        Me.hasValue = True

    End Sub



    Public ReadOnly Property HasValue As Boolean

        Get

            Return Me.hasValue

        End Get

    End Property



    Public ReadOnly Property Value As T

        Get

            If Not Me.HasValue Then

                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue)

            End If

            Return Me.value

        End Get

    End Property



    Public Function GetValueOrDefault() As T

        Return Me.value

    End Function



    Public Function GetValueOrDefault(ByVal defaultValue As T) As T

        If Not Me.HasValue Then

            Return defaultValue

        End If

        Return Me.value

    End Function



    Public Overrides Function Equals(ByVal other As Object) As Boolean

        If Not Me.HasValue Then

            Return (other Is Nothing)

        End If

        If (other Is Nothing) Then

            Return False

        End If

        Return Me.value.Equals(other)

    End Function



    Public Overrides Function GetHashCode() As Integer

        If Not Me.HasValue Then

            Return 0

        End If

        Return Me.value.GetHashCode

    End Function



    Public Overrides Function ToString() As String

        If Not Me.HasValue Then

            Return ""

        End If

        Return Me.value.ToString

    End Function



    Public Shared Widening Operator CType(ByVal value As T) As T?

        Return New T?(value)

    End Operator



    Public Shared Narrowing Operator CType(ByVal value As T?) As T

        Return value.Value

    End Operator

End Structure

以上是Nullable提供的不同种类的方法(包含初始化构造函数,强制类型转换等)。不过有一个有趣的问题——

设想一下把null赋值给Nullable<int>,那么应该系统会调用(C#中,implicit;VB.NET中Widening)那个方法,生成一个新的T类型并传入value。现在问题在于——如果Nullable的泛型类型指定是int,那么对应构造函数的T也是int,你怎么把null赋值给int了呢?

在VB.NET中因为对任意一个值类型赋值Nothing,其实就是初始化这些变量,所以VB.NET很好理解;C#呢?C#是不允许把null赋值给一个值类型的呀!怎么办呢?微软“别出心裁”地在编译时做了手脚(CLR小动作哦!)——注意看,当你在C#中写了:

int? n = null;

其实编译器会将其编译为:

Nullable<int> n = new Nullable<int>();

通过调用默认构造函数来初始化这个int(也就是说——Nullable内部的那个value还是0,只不过HasValue标识默认设置为false,何况微软重写了ToString方法,导致该类型“可空”,说白了根本没有“可空”这回事情,也根本不存在“值类型”=null的东东!)

你可能感兴趣的:(null)