---
title: "C#可空类型与空值运算符"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/csharp-nullable-types-null-operators/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/02-编程语言与运行时/.NET与CSharp/C#可空类型与空值运算符.md"
content_hash: 9eaf7d65e5b7f88e848237711243519514c50d8e0442d09f7fe35e56044d15ed
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
# C#可空类型与空值运算符

> 创建时间：2020/5/20 17:10

参考：<https://blog.csdn.net/qq_42453390/article/details/90403344>

## 可空类型修饰符(?)

引用类型可以使用空引用表示一个不存在的值，而值类型通常不能表示为空。
例如：string str=null; 是正确的，int i=null; 编译器就会报错。
为了使值类型也可为空，就可以使用可空类型

#### System.Nullable variable

#### T? variable

T? 其实是System.Nullable(泛型结构）的缩写形式，也就意味着当你用到T?时编译器编译时会把T？编译成System.Nullable的形式。
T 可以是包括 struct 在内的任何值类型，但不能是引用类型
T? 意思就是 T范围值+ 上可为空的值
**可以为 null 的类型的每个实例都具有两个公共的只读属性：**
**HasValue** ： bool 类型。 当变量包含非 null 值时，它被设置为 true。
**Value** ：Value 的类型与基础类型相同。 如果 HasValue 为 true，则说明 Value 包含有意义的值。 如果 HasValue 为 false，则访问 Value 将引发 InvalidOperationException异常。

> 值类型和引用类型
>  bool, string, int 这些叫做值类型（value type)；
>  Boolean, String, Int32这些叫做引用类型（Reference Type）。
>  值类型存在内存的 **stack（堆栈）** 中。
>  引用类型存在 **heap（堆）** 中。

## 三元(运算符)表达式(?:)

x?y:z

```csharp
string str1 = String.Empty;
string str2 = String.Empty;

str2 = String.Intern(sb.ToString());

if((object)str1==(object)str2)
    Console.WriteLine(&quot;The strings are equal.&quot;);
else
    Console.WriteLine(&quot;The strings are not equal.&quot;);

```

## 空合并运算符(??)

用于定义可空类型和引用类型的默认值。
如果此运算符的左操作数不为null，则此运算符将返回左操作数，否则返回右操作数。
例如：a??b 当a为null时则返回b，a不为null时则返回a本身。

> 空合并运算符为右结合运算符，即操作时从右向左进行组合的。
>  如，“a??b??c”的形式按“a??(b??c)”计算。

## NULL检查运算符（?.）

若要获取一个Point序列的第一个点的X坐标：
int firstX = points.First().X;
但是，老鸟会告诉你， **这儿没有进行NULL检查** ，正确的版本是这样的：

```csharp
string str1 = String.Empty;
string str2 = String.Empty;

str2 = String.Intern(sb.ToString());

if((object)str1==(object)str2)
    Console.WriteLine(&quot;The strings are equal.&quot;);
else
    Console.WriteLine(&quot;The strings are not equal.&quot;);

```

这样写正确，但代码取变得难读多了。
在C# 6.0中，引入了一个 ?. 的运算符，前面的代码可以改成如下形式：
`int? firstX = points?.FirstOrDefault()?.X;`
如果对象为NULL，则不进行后面的获取成员的运算，直接返回NULL

需要注意的是，由于”?.“运算符返回的可以是NULL，当返回的成员类型是struct类型的时候，”?.“和”.”运算符的返回值类型是不一样的。
Point p = new Point(3, 2);
Console.WriteLine(p.X.GetType() == typeof(int)); //true
Console.WriteLine(p?.X.GetType() == typeof(int?)); //true

## (?[])运算符：

int? first = customers?[0].Orders.Count();

## 语法糖

本质：都使用了语法糖，在编译阶段编译器会把特殊符号先转译成原始状态再编译。

> 参考：<https://www.jianshu.com/p/96526064ed38>
>  **语法糖(Syntactic sugar)** ，也译为 **糖衣语法** ，是由英国计算机科学家彼得·约翰·兰达（Peter J. Landin）发明的一个术语，指计算机语言中添加的某种语法，这种语法对语言的功能并没有影响，但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性，从而减少程序代码出错的机会。需要声明的是“语法糖”这个词绝非贬义词，它可以给我们带来方便，是一种便捷的写法，编译器会帮我们做转换；而且可以提高开发编码的效率，在性能上也不会带来损失。
