可空引用类型是C#8.0计划新增的一个功能,不过已经发布了预览版本,今天我们来体验一下可空引用类型。
您必须下载Visual Studio 2017 15.5预览版(目前最新发布版本是15.4),下载地址:https://www.visualstudio.com/en-us/news/releasenotes/vs2017-preview-relnotes。
安装Roslyn扩展预览版本:
在语法上,可为空引用类型与可为空值类型使用的语法是一致的,在类型后面追加 即可。
- class Person
- {
- public string FirstName;
- public string? MiddleName;
- public string LastName;
- }
我们都知道当初微软在增加可为空值类型的时候,实际是在框架中增加了
类型,您肯定会问,可为空引用类型以框架中又增加了什么新的类型。
- System.Nullable<>
我们来看一个演示:
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine(typeof(string?).FullName);
- }
- }
输出结果:
您是否觉得奇怪,怎么输出的是
,是的,其实微软在框架中没有加入任何类型,我们
- System.String
类型进行编译后,再通过doPeek进行反编译,就明白到底发生了什么。
- Person
反编译后的结果:
- internal class Person
- {
- public string FirstName;
- [Nullable]
- public string MiddleName;
- public string LastName;
- }
只是在
字段上增加了
- MiddleName
标记。
- System.Runtime.CompilerServices.NullableAttribute
我们来看一看属性、参数、变量、返回值编译之前与编译之后的比对结果。
属性
- // 编译前:
- public string? MiddleName { get; set; }
- // 编译后:
- [Nullable]
- public string MiddleName { [return: Nullable] get; [param: Nullable] set; }
参数
- // 编译前:
- public Person(string? middleName )
- {
- this.MiddleName = middleName;
- }
- // 编译后:
- public Person([Nullable] string middleName)
- {
- this.MiddleName = middleName;
- }
返回值
- // 编译前:
- public string? DoSomething()
- {
- return null;
- }
- // 编译后:
- [return: Nullable]
- public string DoSomething()
- {
- return (string) null;
- }
变量
- // 编译前:
- string ? name;
- // 编译后:
- string name;
这里除了变量,其它的都使用了
标记进行的修饰。
- NullableAttribute
通过上面的章节,我们知道,可为空引用类型只是在参数、属性、参数和返回值中使用
标记进行修饰,实际上对程序的正常运行没有任何的影响。那么它可以为我们做什么呢?
- NullableAttribute
在C#中不能表达这个变量、参数、字段、属性,返回值等可能为
或不能为
- null
,可为空类型可以帮我们解决这个问题。
- null
- class Person
- {
- public string FirstName; // 不为null
- public string? MiddleName; // 可能为null
- public string LastName; // 不为null
- }
这个类型的可以表示每一个人都应该 FristName 和 LastName ,但是不是每一个人都应该有 MiddleName。
可为空引用类型的另一个好处是编译器可以帮助我们检测代码,比如对于直接使用可为空引用类型的属性,编译器会发出警告。
- void M(Person p)
- {
- p.FirstName = null; // 1 WARNING: Cannot convert null to non-nullable reference。
- p.LastName = p.MiddleName; // 2 WARNING: Possible null reference assignment.
- string s = default(string); // 3 WARNING: Cannot convert null to non-nullable reference。
- if (p.MiddleName != null)
- {
- WriteLine(p.MiddleName.Length); // ok
- }
- WriteLine(p.MiddleName!.Length); // ok
- }
- class Person
- {
- public string FirstName; // 4 WARNING: Non-nullable field 'FirstName' is uninitialized.
- public string? MiddleName;
- public string LastName; // 5 WARNING: Non-nullable field 'LastName' is uninitialized.
- }
编译器会帮我们做以下几点检测:
值或可为空引用类型的值,则会发出警告;
- null
当然这只是编译器的行为,可以禁用与之相关的警告提示。
空引用类型是一个语法糖,只是在编译器的层面帮我们发现可能发生的问题,对程序的正常运行没有任何作用。
参考资料:
来源: http://www.cnblogs.com/tdfblog/p/Nullable-Reference-Types-Preview.html