天天看点

.Net可空值类型

我们在声明一个对象的时候习惯性把该对象声明为null,但是值类型呢,int需要声明为0,DateTime可以声明为DateTime.Now或者Default(DateTime),那么值类型可不可以声明为null呢?答案是可以的!这就是今天的主题,可空值类型。

可空值类型比较简单,先来看一下可空值类型的语法:

语法:

int? value=3;

上面这句话其实就声明了一个可空值类型value,并给该变量赋值3.

也可以这样写:

int? nullValue = null;

这样就可以给该int类型赋一个null值。

如果说要输出该可空值类型的值,应该怎么做呢?可以这样

 Console.WriteLine(value.Value)

调用该变量的Value属性就可以得到该变量的值。

注意:

可空值类型就这么简单么?是的,它的语法就这么简单,使用起来也很方便,不过有些需要注意的地方,

 static void Main(string[] args)

        {

            int? sum = Sum(23, null);

        }

        public static Int32? Sum(Int32? value, Int32? value1)

        {

            return value + value1;

        }

这段代码的结果是什么?23?不对,结果是null(原因会在下来进行讲解)

以下是一些对可空值类型操作符的定义(来自Clr via c#):

.Net可空值类型
.Net可空值类型

为什么结果是null呢?让我们来剖析一下:

可空值类型内部剖析:

 public static Int32? Sum(Int32? value, Int32? value1)

        {

            return value + value1;

        }

让我们用ildasm来看一下这段代码的方法签名:

.method public hidebysig static valuetype [mscorlib]System.Nullable`1<int32>

        Sum(valuetype [mscorlib]System.Nullable`1<int32> 'value',

            valuetype [mscorlib]System.Nullable`1<int32> value1) cil managed

可以看到Int32?被编译成了Nullable<Int32>结构,

在VS中查看该结构的定义是这样的:

    // Summary:

    //     Represents an object whose underlying type is a value type that can also

    //     be assigned null like a reference type.

    //

    // Type parameters:

    //   T:

    //     The underlying value type of the System.Nullable<T> generic type.

    [Serializable]

    [TypeDependency("System.Collections.Generic.NullableComparer`1")]

    [TypeDependency("System.Collections.Generic.NullableEqualityComparer`1")]

    public struct Nullable<T> where T : struct

    {

        //

        // Summary:

        //     Initializes a new instance of the System.Nullable<T> structure to the specified

        //     value.

        //

        // Parameters:

        //   value:

        //     A value type.

        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]

        public Nullable(T value);

        public static explicit operator T(T? value);

        public static implicit operator T?(T value);

        // Summary:

        //     Gets a value indicating whether the current System.Nullable<T> object has

        //     a value.

        //

        // Returns:

        //     true if the current System.Nullable<T> object has a value; false if the current

        //     System.Nullable<T> object has no value.

        public bool HasValue { get; }

        //

        // Summary:

        //     Gets the value of the current System.Nullable<T> value.

        //

        // Returns:

        //     The value of the current System.Nullable<T> object if the System.Nullable<T>.HasValue

        //     property is true. An exception is thrown if the System.Nullable<T>.HasValue

        //     property is false.

        //

        // Exceptions:

        //   System.InvalidOperationException:

        //     The System.Nullable<T>.HasValue property is false.

        public T Value { get; }

        // Summary:

        //     Indicates whether the current System.Nullable<T> object is equal to a specified

        //     object.

        //

        // Parameters:

        //   other:

        //     An object.

        //

        // Returns:

        //     true if the other parameter is equal to the current System.Nullable<T> object;

        //     otherwise, false. This table describes how equality is defined for the compared

        //     values: Return ValueDescriptiontrueThe System.Nullable<T>.HasValue property

        //     is false, and the other parameter is null. That is, two null values are equal

        //     by definition.-or-The System.Nullable<T>.HasValue property is true, and the

        //     value returned by the System.Nullable<T>.Value property is equal to the other

        //     parameter.falseThe System.Nullable<T>.HasValue property for the current System.Nullable<T>

        //     structure is true, and the other parameter is null.-or-The System.Nullable<T>.HasValue

        //     property for the current System.Nullable<T> structure is false, and the other

        //     parameter is not null.-or-The System.Nullable<T>.HasValue property for the

        //     current System.Nullable<T> structure is true, and the value returned by the

        //     System.Nullable<T>.Value property is not equal to the other parameter.

        public override bool Equals(object other);

        //

        // Summary:

        //     Retrieves the hash code of the object returned by the System.Nullable<T>.Value

        //     property.

        //

        // Returns:

        //     The hash code of the object returned by the System.Nullable<T>.Value property

        //     if the System.Nullable<T>.HasValue property is true, or zero if the System.Nullable<T>.HasValue

        //     property is false.

        public override int GetHashCode();

        //

        // Summary:

        //     Retrieves the value of the current System.Nullable<T> object, or the object's

        //     default value.

        //

        // Returns:

        //     The value of the System.Nullable<T>.Value property if the System.Nullable<T>.HasValue

        //     property is true; otherwise, the default value of the current System.Nullable<T>

        //     object. The type of the default value is the type argument of the current

        //     System.Nullable<T> object, and the value of the default value consists solely

        //     of binary zeroes.

        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]

        public T GetValueOrDefault();

        //

        // Summary:

        //     Retrieves the value of the current System.Nullable<T> object, or the specified

        //     default value.

        //

        // Parameters:

        //   defaultValue:

        //     A value to return if the System.Nullable<T>.HasValue property is false.

        //

        // Returns:

        //     The value of the System.Nullable<T>.Value property if the System.Nullable<T>.HasValue

        //     property is true; otherwise, the defaultValue parameter.

        public T GetValueOrDefault(T defaultValue);

        //

        // Summary:

        //     Returns the text representation of the value of the current System.Nullable<T>

        //     object.

        //

        // Returns:

        //     The text representation of the value of the current System.Nullable<T> object

        //     if the System.Nullable<T>.HasValue property is true, or an empty string ("")

        //     if the System.Nullable<T>.HasValue property is false.

        public override string ToString();

    }

该结构提供了一系列对T进行操作的方法,属性。 上述代码我们也可以这样写:   static void Main(string[] args)

        {

            Nullable<int> sum = Sum(23, null);

        }         public static Int32? Sum(Int32? value, Int32? value1)

        {

            return value + value1;

        }

也就是说我们在用int?的时候,编译器实际会把它编译成:Nullable<int>结构,然后对该结构进行操作,该结构重载了对操作符的操作。 装箱和拆箱:  int? a = 3;

 object o = a; 这段代码会导致a进行装箱。 在装箱的过程中,如果a的Value为null,则将null赋给o,此时不会进行装箱操作,如果a的值不是null,则会对int类型的a进行装箱,并将引用赋给o. int? b = (int?)o; 在拆箱过程中,如果o指向的引用值为null,则将b和Value赋为null,此时不会发生拆箱操作,如果o指向的引用值不为null,则将o引用的值通过拆箱操作赋给b. 空接合操作符: 有时我们在给一个变量赋值的时候会这样写:             int? a = 2;

            int? b = a != null ? a : 1; 现在有一种更简单的写法: int? a = 2;

            int? b = a ?? 1;