为了让.Net中的值类型可以赋值为null,微软特地添加了Nullable<T>类型,也可简写为T?。但是Nullable<T>自身是结构体,也是值类型,那么它是如何实现将null赋值给值类型的呢?

下面通过自定义一个可空值类型来讲解Nullable<T>的实现原理。

自定义可空值类型

struct XfhNullable<T> where T : struct
{private T innerValue;//这个属性很重要public bool HasValue { set; get; }public T Value{get{return HasValue ? innerValue: throw new InvalidOperationException();}}public XfhNullable(T value){this.innerValue= value;HasValue = true;}public T GetValueOrDefault(T value){return HasValue ? this.innerValue: value;}public T GetValueOrDefault(){return this.innerValue;}
}

一个可空值类型的结构体大致功能已经定义好了,下面我们来创建可空值类型的实例来验证下。

using static System.Console;class Program
{static void Main(){//使用结构体默认的无参构造函数进行实例化XfhNullable<int> num = new XfhNullable<int>();WriteLine(num.HasValue);WriteLine(null_num.GetValueOrDefault());}
}

可以看到,变量num并不含有值,调用GetValueOrDefault()则会获取它的默认值 0;

这时我们将null赋值给变量num会发现编译器报错Cannot convert null to 'XfhNullable<int>' because it is a non-nullable value type这是因为编译器把我们定义的结构体XfhNullable<T>看作是普通值类型而非可空值类型,所以我们还要添加可空值类型和XfhNullable<T>之间的转换功能。

public static implicit operator XfhNullable<T>(T? nullabelValue)
{if (nullabelValue== null){return new XfhNullable<T>();}return new XfhNullable<T>(nullabelValue.Value);
}

上面的代码实现了可空值类型向XfhNullable<T>的隐式转换,添加上面代码之后发现编译器不再报错。XfhNullable<T>已经成为一个可为null的值类型。

static void Main()
{XfhNullable<int> null_num = null;WriteLine(null_num.HasValue);
}

XfhNullable<T>中的属性HasValue的作用就是标记当前类型是否为null,若是则返回False,否则返回True。当HasValueFalse时调用该类型的Value属性则会抛出异常InvalidOperationException。但可调用GetValueOrDefault()方法来获取类型的默认值。

Nullable<T>类型可以通过运算符==来判断值是否为null,我们也可以通过运算符重载来实现该功能:

public static bool operator ==(XfhNullable<T> cn, object obj)
{if (cn.HasValue){return false;}return true;
}
public static bool operator !=(XfhNullable<T> cn, object obj)
{return !(cn == obj);
}

static void Main()
{XfhNullable<int> null_num = null;WriteLine(null_num == null);
}

接下来,我们来实现普通值类型和XfhNullable<T>之间的转换:

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

static void Main()
{XfhNullable<int> null_num = null;null_num = 12;//int类型隐式转换为XfhNullable<int>类型WriteLine(null_num == null);WriteLine(null_num.Value);int i = (int)null_num;//XfhNullable<int>类型强制转换为int类型
    WriteLine(i);
}

获取实例在运行时的类型:

static void Main()
{XfhNullable<int> null_num = 12;WriteLine(null_num.GetType());
}

这个返回值不大友好,我们希望这里返回内置的值类型,System.Int32,具体实现代码如下:

//因为Object类中的GetType方法不允许子类重写(避免子类隐藏自己的实际类型)
//所以这里使用关键字new来隐藏Object类中的GetType方法
public new Type GetType()
{return innerValue.GetType();
}

结论:没有可为空的值类型

至此,我们已经自定义了一个可为空的值类型XfhNullable<T>,通过以上代码,我们不难发现所谓可为空的值类型是不存在的,它是通过属性HasValue来对null值进行标记的,其内部通过字段innerValue(该字段对应Nullable<T>中的value字段)来维护该类型的值,若被赋值为null则innerValue初始化为值类型的初始值。换句话说,Nullable<T>只是在逻辑层面上实现了把null赋值给值类型,给我们一种值类型可为null的感觉

最后说下可空值类型的装箱与拆箱。
CLR在对Nullable<T>实例执行装箱操作时首先检查它是否为null,若是则CLR不装箱任何东西而是直接返回null;若实例的值不是null则获取该实例的值(Value属性)并对这个值进行装箱操作。
拆箱时,对于null则返回一个Nullable<T>()实例,对于一个具体的数值,如5,则返回Nullable<T>(5)实例。

版权声明

本文为作者原创,版权归作者雪飞鸿所有。 转载必须保留文章的完整性,且在页面明显位置处标明原文链接。

如有问题, 请发送邮件和作者联系。

.NET中可空值类型实现原理相关推荐

  1. 转:SqlServer中的datetime类型的空值和c#中的DateTime的空值的研究

    SqlServer中的datetime类型的空值和c#中的DateTime的空值的研究 在SqlServer 2000中datetime 的空值即默认值为1900-01-01 00:00 :00,C# ...

  2. python中表示空类型的是_python中怎么表示空值

    首先了解python对象的概念 python中,万物皆对象,所有的操作都是针对对象的. 那什么是对象?5是一个int对象,'oblong'是一个str对象,异常也是一个对象,抽象一点是,人,猫,够也是 ...

  3. c# mysql datetime 判断为空 dbnull_转:SqlServer中的datetime类型的空值和c#中的DateTime的空值的...

    SqlServer中的datetime类型的空值和c#中的DateTime的空值的研究 在SqlServer 2000中datetime 的空值即默认值为1900-01-01 00:00 :00,C# ...

  4. c# mysql datetime 判断为空 dbnull_转:SqlServer中的datetime类型的空值和c#中的DateTime的空值的研究...

    SqlServer中的datetime类型的空值和c#中的DateTime的空值的研究 在SqlServer 2000中datetime 的空值即默认值为1900-01-01 00:00 :00,C# ...

  5. .Net C# 中可为空值类型 ?

    在C# 中的可为空值类型表示除了可以接收原有值类型外还可以接收NULL值 例如:int? a =1; int? b=null; 在使用可为空值类型时可以配合 条件运算符 ??  (没错,就是两个问号! ...

  6. c# 数组中的空值_译 | 你到底有多精通 C# ?

    点击上方蓝字关注"汪宇杰博客" 文:Damir Arh 译:Edi Wang 即使是具有良好 C# 技能的开发人员有时候也会编写可能会出现意外行为的代码.本文介绍了属于该类别的几个 ...

  7. C#复习笔记(3)--C#2:解决C#1的问题(可空值类型)

    可空值类型 C#2推出可空类型来表示可以为null的值类型.这是一个呼声很高的需求,因为在常用的数据库中都是允许某些值类型可为空的.那么为什么值类型就不能为空呢?内存中用一个全0的值来表示null,但 ...

  8. 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门)

    by Preethi Kasireddy 通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门) (Why use stati ...

  9. javascript优缺点_为什么要在JavaScript中使用静态类型? 优缺点

    javascript优缺点 by Preethi Kasireddy 通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型? 优缺点 (Why use static t ...

最新文章

  1. 部署tomcat环境
  2. CIKM 2020 | 如何更为合适地评测推荐算法? Top-N物品推荐算法评测设置回顾
  3. Ubuntu 16.04 安装 caffe
  4. 网络编程五种IO模型之poll模型
  5. Linux的进程/线程间通信方式总结
  6. web前端-回调函数sort详解
  7. 【软件开发底层知识修炼】十五 快速学习GDB调试二 使用GDB进行断点调试
  8. 由浅入深了解Thrift(一)——Thrift介绍与用法
  9. STM32 NVIC中断
  10. Linux高可用负载均衡 集群理解
  11. WSL2运行 Anbox
  12. jquery 插件 thickbox窗口 第一个控件获得焦点(解决第二次弹出窗口,文本不能输入数据)...
  13. 嗅探对方机器,获取机器键盘记录
  14. 输入地点名可以直接查询该位置的经度纬度(结合百度地图)
  15. Spring 注解实现原理
  16. python plc fx5u_FX5U系列三菱PLC型号选型一览表
  17. 什么是判断力?如何提高判断力?@HR人才测评
  18. mysql算gps距离_mysql JS 计算两GPS坐标的距离函数:
  19. AutoCAD中程序化加载.NET程序集的方法
  20. 多源bfs Spicy Restaurant

热门文章

  1. python自学网站推荐-有哪些值得推荐的Python学习网站?
  2. SPOJ Pattern Find(Rabin Karp)
  3. mysql中的索引对查询的影响
  4. 网络编程学习笔记(recvfrom很奇怪的一个地方)
  5. keras 模型简介
  6. DFS Tempter of the Bone
  7. [luoguP4306][JSOI2010]连通数
  8. thinkphp联查
  9. jquery的事件对象
  10. JMeter3.0 post参数/BeanShell中文乱码问题