可空类型

可空类型、匿名方法和迭代器这三个优美的特性是在C#2.0里面提出来的。

1、可空类型

当我们在使用数据库的时候,会发现这样的一个矛盾点:数据库的字段设置是允许为null的,比如日期的字段,当你想把数据库表映射为C#中的对象时会发现,DateTime类型在C#语言中是不能为null的!

1.1 简介

可空类型也是值类型,但它是包含null值的值类型:int? nullable=null;

int?就是可空的int类型。很明显,这又是一个语法糖,肯定不会存在int?这样的类型。对于编译器而言,int?会被编译成Nullable<int>类型,即可空类型。

C#2.0中提供的可空类型是Nullable<T>和Nullable(这个T就是一个泛型参数)。在C#中,定义是这样的public struct Nullable<T> where T:struct ,很明显,泛型只能是值类型。下面的代码演示了可空类型的使用方法:

 1 static void Main(string[] args)
 2
 3 {
 4 Nullable<int> value = 1;//int? value=1也可以
 5 Console.WriteLine("可空类型有值的输出情况:");
 6 Display(value);
 7 Console.WriteLine();
 8
 9 value = new Nullable<int>();
10 Console.WriteLine("可空类型没有值的输出情况:");
11 Display(value);
12 Console.ReadKey();
13
14 }
15
16 private static void Display(int? value)
17 {
18 Console.WriteLine("可空类型是否有值:{0}",value.HasValue);
19 if (value.HasValue)
20 {
21 Console.WriteLine("值为:{0}",value.Value);
22 }
23 //如果可空类型有值,则返回Value属性的值,否则就返回默认值
24 Console.WriteLine("GetValueorDefault():{0}",value.GetValueOrDefault());
25 //如果可空类型有值,则返回Value属性的值,否则就返回2
26 Console.WriteLine("GetValueorDefault():{0}", value.GetValueOrDefault(2));
27 //如果HasValue属性为true,则Value属性返回对象的哈希代码,否则为0
28 Console.WriteLine("GetHashCode()方法的使用:{0}",value.GetHashCode());
29 }

1.2 空合并操作符

即为??操作符,它会对左右两个操作数进行判断,如果左边的数不为null,就返回左边的数;如果左边的数为null,就返回右边的数。这个操作符可用于可空类型,也可以用于引用类型,但是不能用于值类型。例如:

1 string stringnotnull="123"
2 string stringisnull=null;
3 string result=stringnotnull ?? "456";
4 string result=stringisnull ?? "12";

以上的代码运行结果为:result=“123”;result2=“12”。

1.3 可空类型的装箱与拆箱操作

既然值类型存在着装箱和拆箱的过程,而可空类型属于值类型,那么它自然也就存在装箱和拆箱操作,下面我们就来看看可空类型的装箱和拆箱的过程。

当把一个可空类型赋给引用类型变量时,CLR会对可空类型(Nullable<T>)对象进行装箱处理。CLR首先检测可空类型是否为null。如果有null,CLR将不会进行实际的装箱操作(因为null可以直接赋值给一个引用类型变量);如果不为null,CLR则从可空类型对象中获取值,并对该值进行装箱(即值类型的装箱过程)。

当把一个已装箱的值类型赋值给可空类型变量时,CLR会对已装箱的值类型进行拆箱处理。如果已装箱值类型的引用为null,则CLR会把可空类型也设为null。

 1 static void Main(string[] args)
 2         {
 3             Console.WriteLine("可空类型的装箱和拆箱的使用如下:");
 4             BoxAndUnbox();
 5             Console.ReadKey();
 6         }
 7
 8         private static void BoxAndUnbox()
 9         {
10             Nullable<int> nullable = 5;
11             int? nullablewithoutvalue = null;
12             Console.WriteLine("读取不为null的可空类型的类型为{0}",nullable.GetType());
13             //出现NullReferenceException的异常
14             //Console.WriteLine("读取为null的可空类型的类型为{0}", nullablewithoutvalue.GetType());
15             object obj = nullable;
16             Console.WriteLine("获得装箱后obj的类型:{0}",obj.GetType());
17
18             int value = (int) obj;
19             nullable = (int?) obj;
20
21             //对一个没有值的可空类型的对象进行装箱操作
22             obj = nullablewithoutvalue;
23             Console.WriteLine("对null的可空类型装箱后obj是否为null:{0}",obj==null);
24
25             //拆箱一定要为可空类型
26             nullable = (int?) obj;
27         }

运行的结果如下:

由以上的结果可以得知:

(1)通过GetType方法来获得赋值的可空类型时,返回的将是赋值的类型,在前面的的代码中即是System.Int32,而不是System.Nullable<System.Int32>类型。

(2)对已赋值的可空类型装箱后,如果使用GetType函数去获得装箱后的引用类型,输出的将仍然是赋值的类型,在前面的代码中即为System.Int32。

(3)如果把一个没有值的可空类型装箱之后再拆箱,不能拆箱为非可空类型的值类型,否则会抛出NullReferenceException异常。因为没有值的可空类型装箱后obj等于null,即引用一个空地址,如果拆箱为非可空类型的值类型,相当于把null赋值给一个int型的变量,而int类型属性值类型,不能被赋值为null,因此会出现异常。

(4)还有一点必须要注意:没有值的可空类型在调用GetType函数之前,编译器会对可空类型进行装箱操作,使其变为null,即空引用。所以之后再调用GetType函数时,就会抛出空引用异常了。

时间: 2024-10-02 12:22:08

可空类型的相关文章

03 php 数据类型:整数,进制转换,浮点,字符,布尔,数组,空类型,类型转换,算术运算,比较运算

03 数据类型:整数,进制转换,浮点,字符,布尔,数组,空类型,类型转换, 算术运算,比较运算,逻辑运算,短路现象, 三目运算符,字符型运算: 数据类型 整体划分 标量类型: int, float, string, bool 复合类型: array,     object 特殊类型: null,     resouce 整数类型int, integer 3种整数表示法 十进制写法:123: $n1 = 123; 八进制写法: 0123 $n2 = 0123; 十六进制写法: 0x123 $n3

Kotlin---------------可空类型与? ?: ?. !!

可空类型主要是为了从编译层面尽可能的减少NPE. 在Kotlin中申明一个变量,如果类型后面不加?则不能直接给此变量赋值为null,在类型后面加上?就变成了可空类型,而可空类型可以直接赋值为null var name: String = null//Error:Null can not be a value of a non-null type String var name1: String? = null//可空类型,可以赋值为null 那么可空类型和普通的类型在使用上有什么区别呢,这就涉及

swift_枚举 | 可为空类型 | 枚举关联值 | 枚举递归 | 树的概念

***************可为空的类型 var demo2 :we_demo = nil 上面这个代码串的语法是错的 为什么呢, 在Swift中,所有的类型定义出来的属性的默认值都不可以是nil 不管是普通简单值类型还是引用类型 那我就是要让这个属性默认值为空,为nil 怎么办呢,很简单,用语法,在定义这个属性的时,在类型后面声明一个? 这样就表示这个属性除了指定类型的默认值外还可以是一个可为空的类型 在Java中,最常见的错误类型就是NullPoinExecption, 为什么就是要有Nu

C# 可空类型

可以为null的类型赋其基础类型正常范围的值和null值. 例如:Nullable<Int32>可以赋值为-2147483618到2147483618之间任意值和null.(int?=null 或int?=9) 在处理数据库和其他包含可能未赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型的功能特别有用. 例如,数据库中的布尔型字段可以存储值 . 例子说明: using System; namespace CalculatorApplication { class Nullables

C#可空类型的速度和GC Alloc测试

在Unity中进行速度和GC Alloc的测试 测试脚本: using UnityEngine; using System; using System.Collections; using System.Diagnostics; public class NullableTest : MonoBehaviour { void Start() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i

空类型指针(void *)的理解

void指针是空类型指针,它不指向任何类型,即void指针仅仅是一个地址,所以空类型指针不能进行指针运算,也不能进行间接引用(因为指针运算和间接引用都需要指针的类型信息). 例如: void * p; //仅仅表示p存放一个地址 p++; //error:+.-运算离不开指针类型 *p=20.5; //error:访问p指向的变量空间需要变量类型信息 由于其他指针都包含有地址信息,所以将其他指针的值赋给空类型指针是合法的:反之,将空类型指针赋给其他指针则不被允许,除非进行显式转换. 例如: in

【C#】可空类型(Nullable)

C# 可空类型(Nullable) C# 提供了一个特殊的数据类型,nullable 类型(可空类型),可空类型可以表示其基础值类型正常范围内的值,再加上一个 null 值. 例如,Nullable< Int32 >,读作"可空的 Int32",可以被赋值为 -2,147,483,648 到 2,147,483,647 之间的任意值,也可以被赋值为 null 值.类似的,Nullable< bool > 变量可以被赋值为 true 或 false 或 null.

动软Model 模板 生成可空类型字段

动软代码 生成可空类型 <#@ template language="c#" HostSpecific="True" #> <#@ output extension= ".cs" #> <# TableHost host = (TableHost)(Host); host.Fieldlist.Sort(CodeCommon.CompareByintOrder); #> using System; using S

关于可空类型

可空类型修饰符“T?”:可空类型的基础类型可以是任何非可空值类型或任何具有struct约束的类型参数,但不能是可空类型或引用类型.例如:int?代表是可空的整形,而int??则是无效类型.即可空类型可以表示其基础类型的所有值和一个额外的空值.语法 T?是System.Nullable<T>的缩写形式.可空类型具有一个HasValue的bool类型只读属性,当可空类型实例的该属性为true时,则表示该实例是非空实例,包含一个已知值Value;HasValue为false时,访问Value属性将导