跟小静读CLR via C#(14)-可空值类型,关于?和??的故事

简介:

我们都知道,值类型是不能为Null的,但是在实际应用中有些情形却需要将值类型置为null。因此,CLR中引用了可空值类型的用法。今天的文章中见到最多的符号估计就是?了吧。


?——初识可空值类型

1.    我们首先看一下可空值类型的声明方法。普通的非空值类型为null时会发生如下的提示:

    clip_image002

但是只要在类型后面缀上个“?”,一切都解决了。此时变量的取值范围在原来基础上添加了一个null。

clip_image004

2.    实际上int? 对应着Nullable<Int32>类型。我们可以查看一下它的IL代码

clip_image006

3.    T?可空值类型包含了两个成员:

  • HasValue:bool类型,如果变量包含非空值,则返回true。否则为false。
  • Value:返回T类型的值。如果该实例为空,则会发生异常。

image

image

 

4.  当定义包含可空值类型的参数时,效率会比非空值类型低一些,它会生成很多的IL代码。 

private double? Add(double? price,int? number)

{

return price * number;

}

clip_image008

可空非空,你来我往

我们可以对可空值类型实例进行转型操作。在转换过程中, 对可空值类型的转换实际上是对Nullable<T>类型变量的转换。我们可以将可空值类型和非空值类型进行相互转换,还可以将可空值类型转换成相应基元类型的可控制类型。

例如:

clip_image010

  • ① 将null隐式转换成 Nullable<T>类型;
  • ② 将int32类型实例隐式转换成Nullable<Int32>类型;
  • ④ 将可空值类型从Nullable<Int32>类型显示转换成Int32类型;
  • ⑤ ⑥将可空值类型转换成相应的基元类型的可控制类型。

当操作符邂逅非空

非空值类型的操作符运算我们都很熟悉,那么当可空值类型遇到操作符,接下来会发生什么事呢?我们主要看一下操作数中包含Null的情况。

1. 一元操作符(+,-,++等):这个很简单,null遇到任何一元操作结果都是null。

2. 相等性操作符(==,!=):

  • 两个值都为null:相等。
  • 其中一个值不为Null:不相等。

3. 关系操作符(>,<,>=,<=):两个操作数任何一个是null,结果就是false。

4. 二元操作符(+,-,*等):一般情况下,任何一个操作符是null,结果就是null。

       不一般的就是&和|: 两个操作数都为Null时,结果为Null,这个好理解;

       当其中一个操作数为null时,情况特殊:

Null&true=null;   null|true=true;   null&false=false;   null|false=null

例如:

image

clip_image012

??

??,叫做“空接合操作符”,以a??b为例, 如果a!=null,则a??b=a;  如果a=null,则a??b=b。

其实它用起来感觉很像三元操作符 ?: ,不过对于方法等支持的更好。当我们把可空赋给非空时,可以用该操作符为其设置默认值。

特色的装箱、拆箱、GetType

之前看值类型那块的时候学过装箱和拆箱过程。CLR支持对可空值类型的装箱拆箱操作,它的流程与非空值类型略有差别:

1. 装箱

我们知道装箱就是将值类型转换为引用类型,可空值类型装箱时首先进行非空检查,如果为null,则直接返回null类型,没有实质上的装箱过程;如果非空,则同对待普通值类型一样进行装箱过程。

int? member1=null;

int member2 = 100;

object o1 = member1;

object o2 = member2;

clip_image014

2. 拆箱

可空值类型的拆箱就是将已装箱的T类型拆为T类型或者Nullable<T>。如果已装箱值类型的引用是null,则拆箱成Nullable<T>的结果也是null,如果想拆成T就会报异常了。

clip_image016

3. GetType()

GetType()方法是返回实例的类型的,前面我们说过可空值类型实际对应的是Nullable<T>类型,那么当调用GetType()方法时,返回的是T还是Nullable<T>呢?

我们眼见为实:

clip_image018

结果为

clip_image020

这也就是说GetType()方法返回的是T,而不是Nullable<T>。

 

相关文章:跟小静读CLR via C#(02)-基元类型、引用类型、值类型 


 

你也许喜欢:跟小静读CLR via C#(00)-开篇及目录





    本文转自 陈敬(Cathy) 博客园博客,原文链接:http://www.cnblogs.com/janes/archive/2011/09/30/2196643.html,如需转载请自行联系原作者

相关文章
|
3月前
|
存储 安全 编译器
C# 11.0中的泛型属性:类型安全的新篇章
【1月更文挑战第23天】C# 11.0引入了泛型属性的概念,这一新特性为开发者提供了更高级别的类型安全性和灵活性。本文将详细探讨C# 11.0中泛型属性的工作原理、使用场景以及它们对现有编程模式的改进。通过深入了解泛型属性,开发者将能够编写更加健壮、可维护的代码,并充分利用C#语言的最新发展。
|
7月前
|
编译器 C#
C#之十七 局部类型
C#之十七 局部类型
17 0
|
1月前
|
存储 C# 开发者
C#变量类型
C#变量类型
18 0
|
3月前
|
开发框架 .NET 编译器
C# 9.0中的目标类型新表达式:类型推断的又一进步
【1月更文挑战第16天】C# 9.0引入了目标类型新表达式,这是类型推断功能的一个重要扩展。通过目标类型新表达式,开发者在创建对象时可以省略类型名称,编译器会根据上下文自动推断所需类型。这一特性不仅简化了代码编写,还提高了代码的可读性和维护性。本文将详细介绍目标类型新表达式的语法、使用场景及其对C#编程的影响。
|
3月前
|
存储 C# 容器
掌握 C# 变量:在代码中声明、初始化和使用不同类型的综合指南
变量是用于存储数据值的容器。 在 C# 中,有不同类型的变量(用不同的关键字定义),例如: int - 存储整数(没有小数点的整数),如 123 或 -123 double - 存储浮点数,有小数点,如 19.99 或 -19.99 char - 存储单个字符,如 'a' 或 'B'。Char 值用单引号括起来 string - 存储文本,如 "Hello World"。String 值用双引号括起来 bool - 存储具有两个状态的值:true 或 false
37 2
|
3月前
|
存储 安全 算法
C# 泛型:类型参数化的强大工具
【1月更文挑战第7天】本文将深入探讨C#语言中的泛型编程,包括泛型的定义、用途、优势以及实际应用。通过类型参数化,泛型允许开发者编写更加灵活且可重用的代码,同时提高程序的类型安全性和性能。本文将通过示例代码和详细解释,帮助读者更好地理解泛型在C#中的重要性和实用性。
|
4月前
|
存储 Java C#
【从Java转C#】第七章:运算符和类型强制转换
【从Java转C#】第七章:运算符和类型强制转换
|
4月前
|
Java 编译器 C#
【从Java转C#】第三章:对象和类型
【从Java转C#】第三章:对象和类型
|
7月前
|
C#
C#中的可空类型修饰符
什么是C#中的可空类型修饰符?如何使用呢?
71 0
|
9月前
|
C#
C#中 Int32.TryParse() ConVert.ToInt32() Int32.Parse () 的区别 将字符串类型转换为数字类型
C#中 Int32.TryParse() ConVert.ToInt32() Int32.Parse () 的区别 将字符串类型转换为数字类型
34 0