C#新特性之可空引用类型

安装

您必须下载Visual Studio 2017 15.5预览版(目前最新发布版本是15.4),下载地址:https://www.visualstudio.com/en-us/news/releasenotes/vs2017-preview-relnotes

安装Roslyn扩展预览版本:

  • 下载并解压 Roslyn_Nullable_References_Preview.zip [最新版本 11/15/17]
  • 关闭所有运行的Visual Studio;
  • 运行zip根目录中的 .\install.bat 脚本(如果需要卸载扩展,可以运行.\uninstall.bat脚本);

语法与类型

在语法上,可为空引用类型与可为空值类型使用的语法是一致的,在类型后面追加 ? 即可。

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,是的,其实微软在框架中没有加入任何类型,我们Person类型进行编译后,再通过dotPeek进行反编译,就明白到底发生了什么。

反编译后的结果:

    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值或可为空引用类型的值,则会发出警告;
  • 如果直接使用可为空引用类型,则会发出警告;
  • 如果从来没有给非可为空引用类型的属性赋值,则会发出警告;
  • 如果需要直接使用可为空引用类型,需要使用 ! 符号告诉编译器,您已经确认过该值不可能为空。

当然这只是编译器的行为,可以禁用与之相关的警告提示。

总结

空引用类型是一个语法糖,只是在编译器的层面帮我们发现可能发生的问题,对程序的正常运行没有任何作用。

到此这篇关于C#新特性之可空引用类型的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解c# 可空类型(Nullable)

    C# 单问号 ? 与 双问号 ?? ? : 单问号用于对 int,double,bool 等无法直接赋值为 null 的数据类型进行 null 的赋值,意思是这个数据类型是 NullAble 类型的. int? i = 3 等同于 Nullable<int> i = new Nullable<int>(3); int i; //默认值0 int? ii; //默认值null ?? : 双问号 可用于判断一个变量在为 null 时返回一个指定的值. 接下来我们详细说明. C# 可空类

  • C#可空类型用法分析

    本文实例讲述了C#可空类型用法.分享给大家供大家参考.具体分析如下: 可空类型只能用于值类型,不能用于引用类型,引用类型本身支持null值. 如果直接把null赋值给int类型,会出现一个错误"无法将 NULL 转换成'int',因为它是一种值类型". 赋值时应该使用 int? a = null; 可空类型与一元或二元运算符一起使用是,如果一个操作数或两个操作数都是null,其结果为null. 说白了int?a=null 这句话的意思就是让值类型a可以接收null这个值 举例1 int

  • C#基础知识 全面解析可空类型

    引言: C# 2.0 中还引入了可空类型,可空类型也是值类型,只是可空类型是包括null的值类型的,下面就介绍下C#2.0中对可空类型的支持具体有哪些内容(最近一直都在思考如何来分享这篇文章的,因为刚开始觉得可空类型使用过程中比较简单,觉得没有讲的必要,但是考虑到这个系列的完整性,决定还是唠叨下吧,希望对一些不熟悉的人有帮助). 一.为什么会有可空类型 如果朋友们看了我之前的分享,对于这一部分都不会陌生,因为我一般介绍C#特性经常会以这样的方式开头的, 因为每个特性都是有它出现的原因的(有一句佛

  • C#中关于可空类型的小知识

    1) 在与1元或二元运算符一起使用时,如果其中一个操作数为null或两个均null,则结果为null. 如: 复制代码 代码如下: int? a = null; int? b = a+3; 则b为null 2) 比较可空类型时,只要有一个操作数为null,结果就为false 如: 复制代码 代码如下: int? a = null; int? b = 8; (a>=b)将返回false 而正是因为null的可能性,所以不能随意比较一个可空类型和一个非可空类型. 3) 空接合运算符 空接合运算符&quo

  • C#基础语法:可空类型详解

    以下是System.Nullable<T>在FCL中的定义. [Serializable, StructLayout(LayoutKind.Sequential)] public struct Nullable<T> where T :struct { private Boolean hasValue= false; internal T value= default(T); public Nullable(T value) { this.value= value; this.ha

  • C# 可空类型的具体使用

    在项目中我们经常会遇到可为空类型,那么到底什么是可为空类型呢?下面我们将从4个方面为大家剖析. 1.可空类型基础知识 顾名思义,可空类型指的就是某个对象类型可以为空,同时也是System.Nullable结构的实例.可空类型可以表示基础值类型正常范围的值,然后再加上一次null值.当然,也可以被赋值null值.比如Nullable<bool>可以被赋值true.false或者null. 声明一个可空类型的标准语句如下: T? myNullableNum = rangedNum/new T?()

  • C# 8.0可空引用类型的使用注意记录

    前言 最近VS2019正式版发布了,装下来顺便试用了一下C#8.0,最大的看点应该就是可空引用类型了.不过C#8.0仍然处于Beta的状态,而且试用时也遇到了几个坑. 背景知识说明: 所谓的可空引用类型是指,一旦启用了可空引用类型这个新特征,引用类型将默认被视为不可空,无法赋予null,除非手工将它设为可空引用类型. 实战示例: 首先是新建一个C#的项目,在 项目文件(.csproj)里加入两行配置,目的是启用"C#8.0语言"和"可空引用类型": <Lang

  • C#难点逐个击破(8):可空类型System.Nullable

    null与void null值用来表示数据类型未被赋予任何值,它是一种引用类型:void表示没有类型,或者说是没有任何值.null与void的区别可以认为void是根本没有,而null是一个空箱子,里面什么都没有. null值只能赋值给引用类型,这里注意到string也是一种引用类型:引用类型在C中称为"指针",即存放变量位置的内存空间位置.将变量设为null,会显式地设置引用,且它本身不指向任何内存位置: null值赋给值类型将导致编译错误. void用于方法值的返回,其本质并不是一

  • C# 可空类型分析

    例如,Nullable<Int32>,读作"可空的 Int32",可以被赋值为 -2147483648 到 2147483647 之间的任意值,也可以被赋值为 null 值.Nullable<bool> 可以被赋值为 true 或 false,或 null.在处理数据库和其他包含可能未赋值的元素的数据类型时,将 null 赋值给数值类型或布尔型的功能特别有用.例如,数据库中的布尔型字段可以存储值 true 或 false,或者,该字段也可以未定义. 可空类型具有

  • 浅谈C# 中的可空值类型 null

    C# 不允许把 null 赋给一个值类型的数据.在 C# 中,以下语句是非法的: 复制代码 代码如下: int a = null;    // 非法 但是,利用 C# 定义的一个修饰符,可将一个变量声明为一个可空(nullable)值类型.可空值类型在行为上与普通值类型相似,但可以将一个 null 值赋给它.如下所示: 复制代码 代码如下: int? a = null;      // 合法 当把一个变量定义为可空值类型时,该变量依然可以被赋值为 0,代码如下所示: 复制代码 代码如下: usi

  • c#可空类型的作用说明

    可空类型用途主要是从数据库读取数据有可能为空,而不是插入使用,插入数据都要进行验证,如果要插入数据库的null,则使用DBNull.value 判断取出的数据是否为数据库中的null,如果是则赋值给可空的datetime类型的Lockdatatime 属性 tseat.Lockdatatime = reader.IsDBNull(5) ? null : (DateTime?)reader.GetDateTime(5); 判断取出的数据是否为数据库中的null,如果是则赋值给可空的int类型的Te

随机推荐