c# 高级编程 5章111页 【泛型】【泛型结构Nullable<T>】【?运算符定义可空类型】

146 阅读2分钟

为什么需要 Nullable<T>

  • 例如,c#中的数字不可为空,而数据库中的数字可为空,这导致二者无法直接映射。
  • 二者映射的解决方案,是将数字变为引用类型,但这会抹杀,值类型低系统开销,这一优点

泛型结构 Nullable<T>

Nullable<T>定义了一个约束,T必须为结构,例如Int32就是一个结构

运算符重载

  • Nullable<T>转换为T,显式定义,需要强转(T)
  • T转换为Nullable<T>隐式定义,因为它总能成功
public struct Nullable<T>
  where T : struct
{
    public Nullable(T value)
    {
        _hasValue = true;
        _value = value;
    }
    
    private bool _hasValue;
    public bool HasValue => _hasValue;
    
    private T _value;
    public T Value
    {
        get
        {
            if(!_hasValue)
            {
                throw new InvalidOperationException("no value");
            }
            return _value;
        }
    }
    
    public static explicit operator T(Nullable<T> value) => _value.Value;
    
    public static implicit operator Nullable<T>(T value) =>
      new Nullable<T>(value);
    
    public override string ToString() => !HasValue? string.Empty : _value.ToString();
    
    }

Nullable<T>的使用

Nullable<int> x;

//将Nullable<int> 当做int来使用
x = 4;
x += 3;

//当做可空int来使用前,要判断一下
if(x.HasValue)
{
    int y = x.Value;
}

//可以为空
x = null;

? 运算符 定义 可空类型

由于Nullable<T>使用频繁, 因此C#提供了一个运算符?定义可空类型

//一样的效果
Nullable<int> x1;
int? x2;

可空类型可以与null,进行比较

//x是int?
if(x == null)
{
    //...
}
else if(x < 0)
{
   //...
}

两个可空类型的变量做算术运算,只要有一个是null,其结果就是null

// x1, x2均为 int?
int? x3 = x1 + x2;

非可空类型转换为可空类型时,隐式转换就行,总是成功的

int y1 = 4;
int? x = y1; //隐式转换,总是成功

可空类型转换为非可空类型时,需要显式转换,当值为null时,会抛出InvalidOperationException

// x1 为 int?
int y1 = (int)x1; //需要 类型强制转换运算符,来进行显式转换

可空类型转换为非可空类型时,可以不用显式转换,而是用合并运算符 ??, 为转换定义一个默认值

// x1 为 int?, 如果x1是null, 就转而使用0
int y1 = x1 ?? 0;