深入理解C#---1.可空类型

来源:互联网 发布:传奇技能数据库 编辑:程序博客网 时间:2024/05/18 03:07
  • 可空类型的核心部分是System.Nullable<T>.
  • 静态类System.Nullable提供了一些工具方法,可以简化可空类型的使用.

首先看一看C#框架中Nullabl<T>的定义:

public struct Nullable<T> where T : struct

很明显,Nullabl<T>是一个泛型类型,泛型参数T有一个值类型约束,同时值类型约束是将可空类型排除在外的,所以Nullable<Nullable<int>>也是不允许的.
T的类型称为可空类型的基础类型(underlying type)

Nullabl<T>最重要的部分就是它的属性,即HasValue和Value

private bool hasValue;public bool HasValue {    get {        return hasValue;        }    }

HasValue是一个简单的Boolean属性,它指出是存在一个真正的值,还是应该将实例视为null

internal T value;public T Value {    get {        if (!hasValue) {            ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);        }        return value;    }}

对于Value,如果存在一个非可空,那么Value表示的就是这个值,如果不存在真正的值,就会抛出一个InvalidOperationException.

Nullabl<T> 引入了一个名为GetValueOrDefault的新方法,它有两个重载方法,如果实例存在值,则返回该值,否则返回一个默认值。其中一个重载方法没有任何参数(在这种情况下会使用基础类型的泛型默认值),另一个重载方法则允许你指定要返回的默认值.

public T GetValueOrDefault() {    return value;}public T GetValueOrDefault(T defaultValue) {    return hasValue ? value : defaultValue;}

Nullabl<T>实现的其他方法全都覆盖了现有的方法:GetHashCode、ToString和Equals.

public override int GetHashCode() {    return hasValue ? value.GetHashCode() : 0;}

GetHashCode会在没有值的时候返回0;如果有值,就返回那个值的GetHashCode.

public override string ToString() {    return hasValue ? value.ToString() : "";}

ToString在没有值的时候返回空字符串,否则返回那个值的ToString.

public override bool Equals(object other) {    if (!hasValue) return other == null;    if (other == null) return false;    return value.Equals(other);}

Equals稍微复杂一些,以后讨论装箱时会谈到它.

最后,框架提供了两个转换.

public static implicit operator Nullable<T>(T value) {    return new Nullable<T>(value);}public static explicit operator T(Nullable<T> value) {    return value.Value;}

首先是T到Nullabl<T>隐式转换。转换结果为一个HasValue属性为true的实例,同样,Nullabl<T>可以显示转换为T,其作用域Value属性相同,在没有真正的值可供返回时将抛出一个异常.

参考《C# in depth》
完整源码

[Serializable][System.Runtime.Versioning.NonVersionable] // This only applies to field layoutpublic struct Nullable<T> where T : struct{    private bool hasValue;    internal T value;    [System.Runtime.Versioning.NonVersionable]    public Nullable(T value) {        this.value = value;        this.hasValue = true;    }            public bool HasValue {        [System.Runtime.Versioning.NonVersionable]        get {            return hasValue;            }        }    public T Value {        get {            if (!hasValue) {                ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue);            }            return value;        }    }    [System.Runtime.Versioning.NonVersionable]    public T GetValueOrDefault() {        return value;    }    [System.Runtime.Versioning.NonVersionable]    public T GetValueOrDefault(T defaultValue) {        return hasValue ? value : defaultValue;    }    public override bool Equals(object other) {        if (!hasValue) return other == null;        if (other == null) return false;        return value.Equals(other);    }    public override int GetHashCode() {        return hasValue ? value.GetHashCode() : 0;    }    public override string ToString() {        return hasValue ? value.ToString() : "";    }    [System.Runtime.Versioning.NonVersionable]    public static implicit operator Nullable<T>(T value) {        return new Nullable<T>(value);    }    [System.Runtime.Versioning.NonVersionable]    public static explicit operator T(Nullable<T> value) {        return value.Value;    }}
0 0