可空类型

为啥要引入可空类型?

在数据库中,字段是可以为null值的,那么在C#中为了方便的操作数据库的值,微软引入了可空类型。

声明可空类型

我们可以使用两种方法声明一个可空类型:

1 Nullable<int> i = null;
2 int? i = null;

第二行是第一行的简写方法,其中“?”是微软为可空类型提供的一个语法糖。

我们看看可空类型的实现:

  1 // Type: System.Nullable`1
  2 // Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
  3 // MVID: 255ABCDF-D9D6-4E3D-BAD4-F74D4CE3D7A8
  4 // Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll
  5
  6 using System.Runtime;
  7
  8 namespace System
  9 {
 10   /// <summary>
 11   /// 表示基础类型为值类型的对象,值类型与引用类型一样也可以分配 null。
 12   /// </summary>
 13   /// <typeparam name="T"><see cref="T:System.Nullable`1"/> 泛型类型的基础值类型。</typeparam><filterpriority>1</filterpriority>
 14   [Serializable]
 15   public struct Nullable<T> where T : struct
 16   {
 17     /// <summary>
 18     /// 将 <see cref="T:System.Nullable`1"/> 结构的新实例初始化为指定值。
 19     /// </summary>
 20     /// <param name="value">一个值类型。</param>
 21     [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
 22     public Nullable(T value);
 23     /// <summary>
 24     /// 创建一个新的 <see cref="T:System.Nullable`1"/> 对象,并将其初始化为指定的值。
 25     /// </summary>
 26     ///
 27     /// <returns>
 28     /// 一个 <see cref="T:System.Nullable`1"/> 对象,其 <see cref="P:System.Nullable`1.Value"/> 属性使用 <paramref name="value"/> 参数进行初始化。
 29     /// </returns>
 30     /// <param name="value">一个值类型。</param>
 31     public static implicit operator T?(T value);
 32     /// <summary>
 33     /// 返回指定的 <see cref="T:System.Nullable`1"/> 的值。
 34     /// </summary>
 35     ///
 36     /// <returns>
 37     /// <paramref name="value"/> 参数的 <see cref="P:System.Nullable`1.Value"/> 属性的值。
 38     /// </returns>
 39     /// <param name="value">一个 <see cref="T:System.Nullable`1"/> 值。</param>
 40     public static explicit operator T(T? value);
 41     /// <summary>
 42     /// 检索当前 <see cref="T:System.Nullable`1"/> 对象的值,或该对象的默认值。
 43     /// </summary>
 44     ///
 45     /// <returns>
 46     /// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则为 <see cref="P:System.Nullable`1.Value"/> 属性的值;否则为当前 <see cref="T:System.Nullable`1"/> 对象的默认值。 默认值的类型为当前 <see cref="T:System.Nullable`1"/> 对象的类型参数,而默认值的值中只包含二进制零。
 47     /// </returns>
 48     [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
 49     public T GetValueOrDefault();
 50     /// <summary>
 51     /// 检索当前 <see cref="T:System.Nullable`1"/> 对象的值或指定的默认值。
 52     /// </summary>
 53     ///
 54     /// <returns>
 55     /// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则为 <see cref="P:System.Nullable`1.Value"/> 属性的值;否则为 <paramref name="defaultValue"/> 参数。
 56     /// </returns>
 57     /// <param name="defaultValue">如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则为一个返回值。</param>
 58     public T GetValueOrDefault(T defaultValue);
 59     /// <summary>
 60     /// 指示当前 <see cref="T:System.Nullable`1"/> 对象是否等于指定的对象。
 61     /// </summary>
 62     ///
 63     /// <returns>
 64     /// 如果 <paramref name="other"/> 等于当前的 <see cref="T:System.Nullable`1"/> 对象,则为 true;否则为 false。 此表描述如何定义所比较值的相等性: 返回值 说明 true <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,并且 <paramref name="other"/> 参数为 null。 即,根据定义,两个 null 值相等。 - 或 - <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,并且 <see cref="P:System.Nullable`1.Value"/> 属性返回的值等于 <paramref name="other"/> 参数。 false 当前 <see cref="T:System.Nullable`1"/> 结构的 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,并且 <paramref name="other"/> 参数为 null。 - 或 - 当前 <see cref="T:System.Nullable`1"/> 结构的 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,并且 <paramref name="other"/> 参数不为 null。 - 或 - 当前 <see cref="T:System.Nullable`1"/> 结构的 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,并且 <see cref="P:System.Nullable`1.Value"/> 属性返回的值不等于 <paramref name="other"/> 参数。
 65     /// </returns>
 66     /// <param name="other">一个对象。</param><filterpriority>1</filterpriority>
 67     public override bool Equals(object other);
 68     /// <summary>
 69     /// 检索由 <see cref="P:System.Nullable`1.Value"/> 属性返回的对象的哈希代码。
 70     /// </summary>
 71     ///
 72     /// <returns>
 73     /// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则为 <see cref="P:System.Nullable`1.Value"/> 属性返回的对象的哈希代码;如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则为零。
 74     /// </returns>
 75     /// <filterpriority>1</filterpriority>
 76     public override int GetHashCode();
 77     /// <summary>
 78     /// 返回当前 <see cref="T:System.Nullable`1"/> 对象的值的文本表示形式。
 79     /// </summary>
 80     ///
 81     /// <returns>
 82     /// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则是当前 <see cref="T:System.Nullable`1"/> 对象的值的文本表示形式;如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则是一个空字符串 ("")。
 83     /// </returns>
 84     /// <filterpriority>1</filterpriority>
 85     public override string ToString();
 86     /// <summary>
 87     /// 获取一个值,指示当前的 <see cref="T:System.Nullable`1"/> 对象是否有值。
 88     /// </summary>
 89     ///
 90     /// <returns>
 91     /// 如果当前的 <see cref="T:System.Nullable`1"/> 对象具有值,则为 true;如果当前的 <see cref="T:System.Nullable`1"/> 对象没有值,则为 false。
 92     /// </returns>
 93     public bool HasValue { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
 94     /// <summary>
 95     /// 获取当前的 <see cref="T:System.Nullable`1"/> 值。
 96     /// </summary>
 97     ///
 98     /// <returns>
 99     /// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则为当前 <see cref="T:System.Nullable`1"/> 对象的值。 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则将引发异常。
100     /// </returns>
101     /// <exception cref="T:System.InvalidOperationException"><see cref="P:System.Nullable`1.HasValue"/> 属性为 false。</exception>
102     public T Value { [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] get; }
103   }
104 }

View Code

我们注意一下其类的声明:

public struct Nullable<T> where T : struct

首先,可空类型是值类型而不是引用类型。

where表明了其接受的类型仅仅是值类型,当然,引用类型天生就支持为null。

使用可空类型

我们来看一个使用可空的例子:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             int? i = null;
10
11             // GetValueOrDefault() 如果为空则返回默认值
12             Console.WriteLine("是否有值:" + i.HasValue + ", 值:" + i.GetValueOrDefault());
13
14             //赋值
15             if (!i.HasValue)
16             {
17                 i = 100;
18             }
19
20             Console.WriteLine("是否有值:" + i.HasValue + ", 值:" + i.Value);
21
22             //int num = i * 2;
23             //上面的写法会报错
24             int num = i.Value * 2;
25             Console.WriteLine("num:" + num);
26
27             if (i == 100)
28             {
29                 Console.WriteLine("等于100");
30             }
31
32             Console.Read();
33         }
34     }
35 }

输出如下:

1 是否有值:False, 值:0
2 是否有值:True, 值:100
3 num:200
4 等于100

空合并操作符

由于可空类型可以为空,所以,如果我们需要获取一个可空类型的值时,如果为null返回0,否则返回其自己的值,写法如下:

int i = nullable.HasValue ? nullable.Value : 0;

我们还可以直接使用GetValueOrDefault();方法来获取,如果是为null需要一个指定的数,如100的写法如下:

1 int i = nullable.HasValue ? nullable.Value : 100;
2 int i = nullable.GetValueOrDefault(100);

上面两种写法的效果一致。

下面我们来看看空合并操作符“??”的效果:判断左方的数,如果不为空则返回左方的数,否则返回右方的数。

比如上面的效果用空合并操作符来写如下:

int i = nullable ?? 100;

我们可以把空操作符看做一种方便的简写形式。

匿名方法

委托、匿名函数、Lambda表达式和事件的学习

闭包

一般一个方法内部定义的值对象会在方法或其作用域结束时被系统回收,但是如果使用匿名函数和Lambda表达式时会引入一种新的情况,导致方法内部定义的值对象不会再方法结束时被回收,这种想象称为闭包。

闭包的概念:主要是指由函数以及与函数相关的上下文环境组成的实体,通过闭包,函数与上下文变量之间建立起关联关系,上下文变量的状态可以在函数的多次调用过程中持久保持,从作用域的角度而言,私有变量的生存期被延长,函数调用所生成的值在下次调用时仍被保持。从安全性的角度而言,闭包有利于信息隐蔽,私有变量只在该函数内可见。

形成闭包的条件:嵌套定义的函数、匿名函数、将函数作为参数或者返回值。

我们来看一个闭包的例子:

 1 using System;
 2
 3 namespace Study
 4 {
 5     class Program
 6     {
 7         static void Main(string[] args)
 8         {
 9             TCloser a = new TCloser();
10             Func<int> b = a.T1();
11             Console.WriteLine(b());
12
13             Console.Read();
14         }
15     }
16
17     public class TCloser
18     {
19         public Func<int> T1()
20         {
21             int n = 999;
22             return () =>
23             {
24                 Console.WriteLine(n);
25                 return n;
26             };
27         }
28     }
29 }

我们会发现,例子中T1的局部变量n,在T1执行完毕后仍然被保留没有被系统回收,而在其返回的方法中可以被使用到,这就是闭包。

迭代器

IEnumerable、IEnumerator与yield的学习

yield学习续:yield return迭代块在Unity3D中的应用——协程

C#学习笔记(六):可空类型、匿名方法和迭代器相关推荐

  1. kolin学习笔记:非空类型与可空类型

    记得在我一开始接触kotlin时,听到的最多的就是kotlin的类型安全,各种巴拉巴拉?,关键就不断的夸安全,其他的却是什么也没有解释,差点还没入门,就直接放弃.虽然确实这是kotlin的特性之一,但 ...

  2. Dart学习笔记六:集合类型详解

    目录 前言 List Set Map 集合的遍历 forEach map where any every 前言 Dart的集合类型使用感觉跟ES6中的集合差不多,这里整理一下Dart集合的常用属性和方 ...

  3. java学习笔记(六)----对象的类型转换, 匿名内置类

    对象的类型转换 --  子类对象可以自动转换成父类 --  父类转换成子类必须使用强制转换 --  instanceof操作符可以用它来判一个实例对象是否属于一个类. class A { public ...

  4. Python学习笔记六——画小猪佩奇

    目录 Python学习笔记六--画小猪佩奇 画布 画笔 属性设置 操纵命令 运动命令 画笔控制命令 全局控制命令 其他命令 Python学习笔记六--画小猪佩奇 使用Python的turtle库可以绘 ...

  5. ROS学习笔记六:理解ROS服务和参数

    ROS学习笔记六:理解ROS服务和参数 主要介绍ROS服务和参数,同时使用命令行工具rosservice和rosparam. ROS service service是节点之间互相通信的另一种方式,se ...

  6. opencv 手选roi区域_【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

  7. JS学习笔记六:js中的DOM操作

    1. JS学习笔记六:js中的DOM操作 文章目录 1. JS学习笔记六:js中的DOM操作 1.1. 获取Dom节点 1.2. 元素属性的操作方式 1.3. DOM节点的创建.插入和删除 1.4. ...

  8. 【K210】K210学习笔记六——MaixHub在线模型训练识别数字

    [K210]K210学习笔记六--MaixHub在线模型训练识别数字 前言 K210准备工作 数据的获取 MaixHub如何在线训练模型 训练模型在K210上的测试 小结 前言 本人大四学生,电赛生涯 ...

  9. Java学习笔记 六、面向对象编程中级部分

    Java学习笔记 六.面向对象编程中级部分 包 包的注意事项和使用细节 访问修饰符 访问修饰符的注意事项和使用细节 面向对象编程三大特征 封装 封装的实现步骤(三步) 继承 继承的细节问题 继承的本质 ...

  10. libevent学习笔记六:libevent核心事件event

    libevent学习笔记六:libevent核心事件event 前面对reactor模式.事件处理流程.libevent源代码结构等有了高层的认识后,接下来将详细介绍libevent的核心结构even ...

最新文章

  1. 如何在Linux系统上自动执行任务
  2. 如何在高并下设置Linux系统及kernel参数
  3. 第一节、Alex 讲解 python+mysql 交互;
  4. BZOJ 1012 [JSOI2008]最大数maxnumber
  5. 训练过程acc_AI 深度学习训练tricks总结(均有实验支撑)
  6. 什么是堆栈的构造方法?向上生长堆栈,向下生长堆栈
  7. Confluence 6 让一个空间可以公众访问
  8. Mybatis 有坑,千万别踩!
  9. C语言向文件写入学生信息并读取显示出来
  10. 【转】 Git 常用命令详解(二)----不错
  11. 好消息!电商工具箱API详情接口,更全面
  12. 昂达平板不能开机刷机_昂达平板电脑刷机教程
  13. flash spi w25q128 w25q64 w25q32 w25q16 verilog fpga程序代码
  14. 个人备案网站不能做博客了?
  15. UE4加载Excel表格CSV数据及解决中文乱码问题
  16. PCL——点云特征描述与提取
  17. Linux编写C++程序
  18. 浙大计算机专业是不是图灵班,浙大图灵班录取条件
  19. 【前端三分钟】利用Javascript实现打字效果
  20. 学士峡谷风景Mac壁纸分享

热门文章

  1. java开发组态软件下载_基于JAVA的煤矿安全监控系统组态软件设计研究.pdf
  2. c语言一串大写字母转小写,C语言的基础函数大小写转换
  3. 织梦php 中英文加手机,织梦dedecms系统中英文网站之中英文搜索结果
  4. python用变量输出abcd_python中星号变量的几种特殊用法
  5. java编译不了testpad,java – Gradle编译但不运行TestNG测试
  6. tornado celery mysql_Python3.7+Tornado5+Celery3+Rabbitmq3实现异步队列任务
  7. php mysql迭代器_php 迭代器
  8. 机器学习实践:本地远程查看服务器训练TensorBoard
  9. “山东土地集团杯”暨滨州市数据应用创新创业大赛正式启动!
  10. 【深度学习】449页pdf,FaceBook称其迈出“重塑AI科学的第一步”