C#可空类型

可空类型为值类型提供了和引用类型相似的null的概念。

声明

语法:

类型? 变量;
int? i = 100;
int? j = null;

可空类型是System.Nullable<T>类型语法糖。

可空类型的成员

namespace System
{
    public struct Nullable<T> where T : struct
    {
        //根据基础对象创建可空类型。
        public Nullable(T value);

        //判断对象是否具有值。
        public Boolean HasValue{get;}

        //获取基础值,如果没有值则抛出异常
        public T Value { get;}

        //和另一对象判断是否相等。
        public override Boolean Equals(Object other);

        //获取对象的哈希代码。
        public override Int32 GetHashCode();

        //获取对象的值或默认值。
        public T GetValueOrDefault();

        //获取对象的值或返回提供的默认值。
        public T GetValueOrDefault(T defaultValue);

        //返回对象的值的文本表示形式。
        public override String ToString();

        //隐式由基础值创建可空对象。
        public static implicit operator Nullable<T> (T value);

        //显示转换为基础类型,没有基础值抛出异常。
        public static explicit operator T(Nullable<T> value);
    }
}

上面的代码等价于

Nullable<int> i = new Nullable<int>(100);
Nullable<int> j = new Nullable<int>();

判断非空和取值

int? i = 100;
if(i!=null){
    int value = (int)i;
}

等价于

Nullable<int> i = new Nullable<int>(100);
if(i.HasValue){
    int value = i.Value;
}

装箱

将可空类型装箱,如果有值,装箱的是基本值;如果没有值,装箱为null

int? i = 100;
object o1 = i;//o1是100
int? j = null;
object o2 = j;//o2是null

接口

可空类型自身没有实现任何接口,但允许其转换成基本类型实现的接口

int? i =100;
IComparable<int> comparable = i;

这是由于转换成接口时发生了装箱,装箱后可空类型是基本类型。

获取类型

可空类型变量的GetType方法获取的是基础类型。

int? i = 100;
Type t = i.GetType();//System.Int32

这是由于GetTypeobject的方法,中间发生了装箱,装箱后可空类型是基本类型。

反射获取类型时,可以获取原始类型。

class F
{
    public int? Value{get;set;}
}

Type t = typeof(F).GetProperty("Value").PropertyType;//Nullable<Int32>

运算

可空类型可以使用运算符进行运算。

可空类型的算数运算

int? i =10;
int? j =null;
int? sum = i + j;//null

对于算数运算,如果有任何一个操作数为null,结果就是null

可空类型的关系运算

int? i =10;
int? j =null;
int? k = null;
bool isGreater = i>j;//false
bool isEqual = i==j;//false
bool isLess = i <j;//false
bool isEqual2 = j == k;//true
bool isEqula3 = i == i;//true

对于关系运算,如果是相等比较,则同时为null相等,有一个为null则不相等,否则比较基础值。

如果是大小比较,如果有任何一个操作数为null,结果就是false,否则比较基础值。

可空类型的逻辑运算

可空类型的逻辑运算只支持非!

bool? a = true;
bool? b = null;
bool? c = false;
bool? bNot1 = !a;//false
bool? bNot2 = !b;//null
bool? bNot3 = !c;//true

bool?类型的位运算

以下是bool?类型各个值和null的运算结果。

位与

& true false null
null null false null

位或

| true false null
null true null null

位亦或

^ true false null
null null null null

其它可空类型的位运算

int? a = 10;
int? b = null;
int? bitAnd = a & b;
int? bitOr = a | b;
int? bitXor = a ^ b;
int? bitNot = ~b;

如果操作数有为null的,则结果为null

可空类型的位移运算

int? a = null;
int? v1 = a << 2;
int? v2 = a >> 2;

操作数为null则结果为null

可空类型和泛型约束

可空类型虽然是结构,但是不能传递给泛型约束为struct的成员。

可空类型不能嵌套使用(受限于上一条)。

相应的,泛型约束为struct时,可以使用T?类型。

public static bool IsNull<T>(T? value) where T : struct
{
    return value == null;
}

public static string ToString<T>(T? value, string format) where T : struct, IFormattable
{
    return value == null ? string.Empty : value.Value.ToString(format, null);
}