可空类型Nullable Types

引用类型通过使用Null引用就可以表示一个不存在的值。
Reference types can represent a nonexistent value with a null reference.

然而,值类型通常就无法表示空值了。
Value types,however, cannot ordinarily represent null values.
未命名图片.png
要在值类型里表示null值,你必须使用一种特殊的构造,它叫做可空(值)类型
To represent null in value type,you must use a special construct called a nullable type.

可空值类型是这样表示的:前面就是一个值类型,他后面跟着一个?(问号)
A nullable type is denoted with a value type followed by the ? symbol
未命名图片.png

Nullable结构体(Struct)

  • T?这种写法表示的可空类型会被翻译成System.Nullable.而System.Nullable是一种轻量级不可变的结构,它只有两个字段(Value和HasValue),这两个字段分别表示真正的值(如果不是Null的话)和是否有非Null值。

未命名图片.png

  1. int? i = null;
  2. Console.WriteLine(i == null);
  • 会被翻译成

    1. Nullable<int> i = new Nullable<int>();
    2. Console.WriteLine(!i.HasValue); // True
  • 无参的GetValueOrDefault()方法在HasValue为True的时候,会返回结构体里的值,如果HasValue为false,那么返回该类型的默认值。

  • 有参的GetValueOrDefault(T defaultvalue)方法,在HasValue为false的情况下,会返回结构体里面的值或者通过方法参数指定的这个默认值。
  • objec里面定义的Equals(object)和GetHashCode()这两个方法也被相应的重写了,首先会比较HasValue属性的值,如果两个被比较对象的HasValue属性都是true,那么然后就会比较Value属性的相等性。
  • 如果在HasValue为false的情况下,想去尝试获取Value的值,那么就会抛出InvalidOperationException
  • 如果HasValue为true的话,那么GetValueOrDefault()方法就会返回该类型真正的值;否则的话,它会返回new T()或者是指定的自定义默认值。
  • T?默认值是null。

Nullable的简化版源码

  1. public struct Nullable<T> where T : struct
  2. {
  3. private readonly T value;
  4. private readonly bool hasValue;
  5. public Nullable(T value)
  6. {
  7. this.value = value;
  8. this.hasValue = true;
  9. }
  10. public bool HasValue { get { return hasValue; } }
  11. public T Value
  12. {
  13. get
  14. {
  15. if (!hasValue)
  16. {
  17. throw new InvalidOperationException();
  18. }
  19. return value;
  20. }
  21. }
  22. }
  • 这里已声明的构造函数把hasValue这个字段值设为了true。
  • 和其他结构体一样,它也有一个隐式的无参构造函数。在哪里hasValue的值原封不动,就是false;而value的值就是T的默认值。
  • 以上代码中,作用于Nullable的where T:struct这个约束,它允许T可以使任意的值类型,但不可以是Nullable.
  • 下面这些都是不合法的:
    • Nullable(string是引用类型)
    • Nullable(数组是引用类型)
    • Nullable(Enum本事不是值类型)
    • Nullable>(Nullable是可空的)
    • Nullable>>(嵌套着用也不行!。。)