C#学习笔记(六):可空类型、匿名方法和迭代器
可空类型
为啥要引入可空类型?
在数据库中,字段是可以为null值的,那么在C#中为了方便的操作数据库的值,微软引入了可空类型。
声明可空类型
我们可以使用两种方法声明一个可空类型:
Nullable<int> i = null;
int? i = null;
第二行是第一行的简写方法,其中“?”是微软为可空类型提供的一个语法糖。
我们看看可空类型的实现:
// Type: System.Nullable`1
// Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 255ABCDF-D9D6-4E3D-BAD4-F74D4CE3D7A8
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll using System.Runtime; namespace System
{
/// <summary>
/// 表示基础类型为值类型的对象,值类型与引用类型一样也可以分配 null。
/// </summary>
/// <typeparam name="T"><see cref="T:System.Nullable`1"/> 泛型类型的基础值类型。</typeparam><filterpriority></filterpriority>
[Serializable]
public struct Nullable<T> where T : struct
{
/// <summary>
/// 将 <see cref="T:System.Nullable`1"/> 结构的新实例初始化为指定值。
/// </summary>
/// <param name="value">一个值类型。</param>
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public Nullable(T value);
/// <summary>
/// 创建一个新的 <see cref="T:System.Nullable`1"/> 对象,并将其初始化为指定的值。
/// </summary>
///
/// <returns>
/// 一个 <see cref="T:System.Nullable`1"/> 对象,其 <see cref="P:System.Nullable`1.Value"/> 属性使用 <paramref name="value"/> 参数进行初始化。
/// </returns>
/// <param name="value">一个值类型。</param>
public static implicit operator T?(T value);
/// <summary>
/// 返回指定的 <see cref="T:System.Nullable`1"/> 的值。
/// </summary>
///
/// <returns>
/// <paramref name="value"/> 参数的 <see cref="P:System.Nullable`1.Value"/> 属性的值。
/// </returns>
/// <param name="value">一个 <see cref="T:System.Nullable`1"/> 值。</param>
public static explicit operator T(T? value);
/// <summary>
/// 检索当前 <see cref="T:System.Nullable`1"/> 对象的值,或该对象的默认值。
/// </summary>
///
/// <returns>
/// 如果 <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"/> 对象的类型参数,而默认值的值中只包含二进制零。
/// </returns>
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public T GetValueOrDefault();
/// <summary>
/// 检索当前 <see cref="T:System.Nullable`1"/> 对象的值或指定的默认值。
/// </summary>
///
/// <returns>
/// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则为 <see cref="P:System.Nullable`1.Value"/> 属性的值;否则为 <paramref name="defaultValue"/> 参数。
/// </returns>
/// <param name="defaultValue">如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则为一个返回值。</param>
public T GetValueOrDefault(T defaultValue);
/// <summary>
/// 指示当前 <see cref="T:System.Nullable`1"/> 对象是否等于指定的对象。
/// </summary>
///
/// <returns>
/// 如果 <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"/> 参数。
/// </returns>
/// <param name="other">一个对象。</param><filterpriority></filterpriority>
public override bool Equals(object other);
/// <summary>
/// 检索由 <see cref="P:System.Nullable`1.Value"/> 属性返回的对象的哈希代码。
/// </summary>
///
/// <returns>
/// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则为 <see cref="P:System.Nullable`1.Value"/> 属性返回的对象的哈希代码;如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则为零。
/// </returns>
/// <filterpriority></filterpriority>
public override int GetHashCode();
/// <summary>
/// 返回当前 <see cref="T:System.Nullable`1"/> 对象的值的文本表示形式。
/// </summary>
///
/// <returns>
/// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则是当前 <see cref="T:System.Nullable`1"/> 对象的值的文本表示形式;如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则是一个空字符串 ("")。
/// </returns>
/// <filterpriority></filterpriority>
public override string ToString();
/// <summary>
/// 获取一个值,指示当前的 <see cref="T:System.Nullable`1"/> 对象是否有值。
/// </summary>
///
/// <returns>
/// 如果当前的 <see cref="T:System.Nullable`1"/> 对象具有值,则为 true;如果当前的 <see cref="T:System.Nullable`1"/> 对象没有值,则为 false。
/// </returns>
public bool HasValue { [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get; }
/// <summary>
/// 获取当前的 <see cref="T:System.Nullable`1"/> 值。
/// </summary>
///
/// <returns>
/// 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 true,则为当前 <see cref="T:System.Nullable`1"/> 对象的值。 如果 <see cref="P:System.Nullable`1.HasValue"/> 属性为 false,则将引发异常。
/// </returns>
/// <exception cref="T:System.InvalidOperationException"><see cref="P:System.Nullable`1.HasValue"/> 属性为 false。</exception>
public T Value { [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] get; }
}
}
我们注意一下其类的声明:
public struct Nullable<T> where T : struct
首先,可空类型是值类型而不是引用类型。
where表明了其接受的类型仅仅是值类型,当然,引用类型天生就支持为null。
使用可空类型
我们来看一个使用可空的例子:
using System; namespace Study
{
class Program
{
static void Main(string[] args)
{
int? i = null; // GetValueOrDefault() 如果为空则返回默认值
Console.WriteLine("是否有值:" + i.HasValue + ", 值:" + i.GetValueOrDefault()); //赋值
if (!i.HasValue)
{
i = ;
} Console.WriteLine("是否有值:" + i.HasValue + ", 值:" + i.Value); //int num = i * 2;
//上面的写法会报错
int num = i.Value * ;
Console.WriteLine("num:" + num); if (i == )
{
Console.WriteLine("等于100");
} Console.Read();
}
}
}
输出如下:
是否有值:False, 值:
是否有值:True, 值:
num:
等于100
空合并操作符
由于可空类型可以为空,所以,如果我们需要获取一个可空类型的值时,如果为null返回0,否则返回其自己的值,写法如下:
int i = nullable.HasValue ? nullable.Value : ;
我们还可以直接使用GetValueOrDefault();方法来获取,如果是为null需要一个指定的数,如100的写法如下:
int i = nullable.HasValue ? nullable.Value : ;
int i = nullable.GetValueOrDefault();
上面两种写法的效果一致。
下面我们来看看空合并操作符“??”的效果:判断左方的数,如果不为空则返回左方的数,否则返回右方的数。
比如上面的效果用空合并操作符来写如下:
int i = nullable ?? ;
我们可以把空操作符看做一种方便的简写形式。
匿名方法
闭包
一般一个方法内部定义的值对象会在方法或其作用域结束时被系统回收,但是如果使用匿名函数和Lambda表达式时会引入一种新的情况,导致方法内部定义的值对象不会再方法结束时被回收,这种想象称为闭包。
闭包的概念:主要是指由函数以及与函数相关的上下文环境组成的实体,通过闭包,函数与上下文变量之间建立起关联关系,上下文变量的状态可以在函数的多次调用过程中持久保持,从作用域的角度而言,私有变量的生存期被延长,函数调用所生成的值在下次调用时仍被保持。从安全性的角度而言,闭包有利于信息隐蔽,私有变量只在该函数内可见。
形成闭包的条件:嵌套定义的函数、匿名函数、将函数作为参数或者返回值。
我们来看一个闭包的例子:
using System; namespace Study
{
class Program
{
static void Main(string[] args)
{
TCloser a = new TCloser();
Func<int> b = a.T1();
Console.WriteLine(b()); Console.Read();
}
} public class TCloser
{
public Func<int> T1()
{
int n = ;
return () =>
{
Console.WriteLine(n);
return n;
};
}
}
}
我们会发现,例子中T1的局部变量n,在T1执行完毕后仍然被保留没有被系统回收,而在其返回的方法中可以被使用到,这就是闭包。
迭代器
IEnumerable、IEnumerator与yield的学习
yield学习续:yield return迭代块在Unity3D中的应用——协程
C#学习笔记(六):可空类型、匿名方法和迭代器的更多相关文章
- [读书笔记]C#学习笔记四: C#2.0泛型 可控类型 匿名方法和迭代器
前言 C#1.0的委托特性使方法作为其他方法的参数来传递,而C#2.0 中提出的泛型特性则使类型可以被参数化,从而不必再为不同的类型提供特殊版本的实现方法.另外C#2.0还提出了可空类型,匿名方法和迭 ...
- C#学习笔记三: C#2.0泛型 可控类型 匿名方法和迭代器
前言 C#1.0的委托特性使方法作为其他方法的参数来传递,而C#2.0 中提出的泛型特性则使类型可以被参数化,从而不必再为不同的类型提供特殊版本的实现方法.另外C#2.0还提出了可空类型,匿名方法和迭 ...
- Python学习笔记:set集合类型所有方法汇总
################################################## 集合的作用是:# 1.获得两个集合之间某种关系的集合(比如求两个集合的交集)# 2.计算集合之间的 ...
- javascript学习笔记(四) Number 数字类型
数字格式化方法toFixed().toExponential().toPrecision(),三个方法都四舍五入 toFixed() 方法指定小数位个数 toExponential() 方法 用科学 ...
- java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)
java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...
- Typescript 学习笔记六:接口
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- 【opencv学习笔记六】图像的ROI区域选择与复制
图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...
- Spring Boot 学习笔记(六) 整合 RESTful 参数传递
Spring Boot 学习笔记 源码地址 Spring Boot 学习笔记(一) hello world Spring Boot 学习笔记(二) 整合 log4j2 Spring Boot 学习笔记 ...
- Redis学习笔记六:持久化实验(AOF,RDB)
作者:Grey 原文地址:Redis学习笔记六:持久化实验(AOF,RDB) Redis几种持久化方案介绍和对比 AOF方式:https://blog.csdn.net/ctwctw/article/ ...
- Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
随机推荐
- HDU 3746 (KMP求最小循环节) Cyclic Nacklace
题意: 给出一个字符串,要求在后面添加最少的字符是的新串是循环的,且至少有两个循环节.输出最少需要添加字符的个数. 分析: 假设所给字符串为p[0...l-1],其长度为l 有这样一个结论: 这个串的 ...
- 如何使用jetty
一直都听说jetty跟Tomcat一样,是一个web容器.之前做项目的时候,也使用过jetty,不过当时jetty是作为一个插件,跟maven集成使用的.那个时候,由于是第一次使用jetty,感觉je ...
- [反汇编练习]160个CrackMe之001
[反汇编练习] 160个CrackMe之001. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...
- UVA 820 Internet Bandwidth 因特网宽带(无向图,最大流,常规)
题意:给一个无向图,每条边上都有容量的限制,要求求出给定起点和终点的最大流. 思路:每条无向边就得拆成2条,每条还得有反向边,所以共4条.源点汇点已经给出,所以不用建了.直接在图上跑最大流就可以了. ...
- Java [leetcode 7] Reverse Integer
问题描述: Reverse digits of an integer. Example1: x = 123, return 321 Example2: x = -123, return -321 Ha ...
- hdu 3535 AreYouBusy
// 混合背包// xiaoA想尽量多花时间做ACM,但老板要求他在T时间内做完n堆工作,每个工作耗时ac[i][j],// 幸福感ag[i][j],每堆工作有m[i]个工作,每堆工作都有一个性质,/ ...
- 【转】自定义iOS的Back按钮(backBarButtonItem)和pop交互手势(interactivepopgesturerecognizer) --- 不错
原文网址:http://blog.csdn.net/joonsheng/article/details/41362499 序 说到自定义UINavigetionController的返回按钮,iOS7 ...
- 为SQL表添加全文索引范例
--范例: --为HR_Job中的JobTitle,JobDes创建全文索引 execute sp_fulltext_catalog 'boli188', 'create' --创建全文目录,boli ...
- asp.net MVC 应用程序的生命周期(上)
首先我们知道http是一种无状态的请求,他的生命周期就是从客户端浏览器发出请求开始,到得到响应结束.那么MVC应用程序从发出请求到获得响应,都做了些什么呢? 本文我们会详细讨论MVC应用程序一个请求的 ...
- 浅谈Linux容器和镜像签名
导读 从根本上说,几乎所有的主要软件,即使是开源软件,都是在基于镜像的容器技术出现之前设计的.这意味着把软件放到容器中相当于是一次平台移植.这也意味着一些程序可以很容易就迁移,而另一些就更困难. 我大 ...