滨州信息港:.NET项目升级手记:可为空引用

admin 4天前 科技 14 2

c# 8引入了新特征:“可为空引用”(详情),这个功效小我私家以为挺好的,能够异常明确的显示程序设计者的意图,编译器能够举行检查,尽最大可能减小NullReferenceException错误。

若是是新项目,那么上手很简单,一点点搭建起来,遇山开山,遇河渡河。然则对于我这种手头上的项目大多都是以前建立的情形,就要稍微做那里么一点操作了。

要看完整说明,请查看开头的谁人链接。

准备

首先评估一下几个条件:

  1. 项目可以基于.NET CORE 3.0及以上编译。若是不行,那么就请直接右上角点×。
  2. 是不是大多数的变量都需要null引用?若是是的话,小我私家以为不值得费劲了。

操作

以一个ASP.NET WEBAPI为例,项目修改前是能够正常编译无错误无忠告的。

1. 启用NullABLe(可为空引用类型)

Nullable默认是不启用的,需要做一些修改以启用。有两种方式:

  • 修改csproj文件,在ProperyGroup内里添加 enable项。

对于对照小型的项目,可以直接修改,这样弹出来的忠告或者错误会对照少,利便我们快速矫正。

  • 使用编译器指令#nullable enable和#nullable restore举行修改。在代码段的开头enable,结尾处restore。

对于中大型项目,直接使用第一种方式举行修改会导致大量的忠告,很容易一团糟;可以通过编译器指令对单文件或者单类举行修改操作,一点一点地修改。

2. 修改代码

我的项目使用第一种方法的的情形下有24个忠告(编译后有67个),也不知道算多照样算少。

实体类

[DataContract]
    [Table("recordinfo")]
    public class RecordInfo : InfoBase
    {
        /// <summary>
        /// 纪录ID
        /// </summary>
        [DataMember]
        [Key]
        public string RecordNum { get; set; }
        /// <summary>
        /// 车辆RFID号码
        /// </summary>
        [DataMember]
        public string CarID { get; set; }

RecordNum为主键,通过EF举行映射,效果也不会为null,以是声明应该保持原样即可。CarID不是主键,有可能是null,因此应当显式声明为string?,示意可以为空,删除忠告。

编译器检查,RecordNum没有被初始化,我们的设计意图告诉编译器了,然则代码还没有保证这个不能为空,因此需要修改代码保证RecordNum不为空。

这里使用null包容运算符(!)来举行操作,提醒编译器这个位置实际上不会为null。

//string的default为null,通过增添!告诉编译器,这块初始化的时刻实际上是不为空的。
public string RecordNum { get; set; } = default!;

null包容运算符并不能确保不是null,若是可以使用代码确保不为null,那么使用代码会是更优选择。思量如下代码:

//我经常使用String.IsNullOrWhiteSpace来举行检查,空文本对我的营业没有意义,因此适用。
public string RecordNum { get; set; } = "";

稀奇提醒:
可为空引用类型检查是编译器的行为,它可以提供编译时检查,然则不提供运行时检查,若是使用外部代码挪用,那么是否为空都可以举行赋值。

很明显,上面代码运行时也很难保证不是null,我们可以再改善一下。

public string RecordNum
{
    get => recordNum;
    set => recordNum = value ?? "";
}
private string recordNum = "";

官方推荐对POCO类使用组织函数保证不为空。
指定了default!的情形,ASP.NET CORE WEBAPI会内部自动标注[Required],远程挪用若是缺失参数,会提醒bad request。

DataContext类

DataContext也是类似的,主要是DbSet工具的引用问题

来自.NET Class Library

//BaseDirectory的返回是string?类型的
var baseDirectory = System.AppDomAIn.CurrentDomain.BaseDirectory;
//Path.Combine()不接受string?,提醒错误。
var xmlPath = Path.Combine(baseDirectory, System.AppDomain.CurrentDomain.FriendlyName + ".xml");

这是一个潜在的bug点,对于以上代码,很显然BaseDirectory的返回为null不符合我们的设计,我们可以举行如下革新。

var baseDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
if (baseDirectory == null) throw new ArgumentNullException("baseDirectory");
var xmlPath = Path.Combine(baseDirectory, System.AppDomain.CurrentDomain.FriendlyName + ".xml");

泛型类

public class ReturnData<T>
{
    //整个类型会提醒Data未能初始化,ErrorMsg未能初始化。
    public ReturnData(){ }
    public ReturnData(T data) => Data = data;
    public ReturnData(string error) => ErrorMsg = error;
    /// <summary>
    /// 页面数据
    /// </summary>
    public T Data { get; set; }
    public string ErrorMsg { get; set; }
}

设计意图:Data与ErrorMsg差别时为空,也差别时有值。

基于设计,可以做如下修改。注重添加了class约束。

public class ReturnData<T>
    where T: class
{
    public ReturnData(){ }
    public ReturnData(T data) => Data = data;
    public ReturnData(string error) => ErrorMsg = error;
    /// <summary>
    /// 页面数据
    /// </summary>
    public T? Data { get; set; }
    public string? ErrorMsg { get; set; }
}

其他例子

using ManageDataContext context = new ManageDataContext();
var props = contextType.GetProperty($"{namestring}s");
//props提醒有可能为null
var dbset = (props.GetValue(context) as DbSet<T>);
//提醒dbset可能为null
var res = await dbset.FindAsync(value);

可以调整为下面的形式:

using ManageDataContext context = new ManageDataContext();
var props = contextType.GetProperty($"{namestring}s");
//判断props可以解决问题。
if (props == null) throw new ArgumentNullException("Props");
var dbset = (props.GetValue(context) as DbSet<T>);
//判断dbset可以解决问题。
if (dbset == null) throw new ArgumentNullException("dbset");
var res = await dbset.FindAsync(value);

注重,将as替换为强制转换,并不能消除忠告。

总结

最后消除了所有的忠告,革新竣事。

这个新的语言特征可以辅助我们发现一些潜在的bug点,辅助我们养成优越的编程习惯,也便于我们告诉其他人我们的设计意图。

编译器能帮我们做的事情,就没必要自己再费劲做了,懒的不行,我得歇会儿。

,

阳光在线

阳光在线www.sinotter.com(原诚信在线)现已开放阳光在线手机版下载。阳光在线游戏公平、公开、公正,用实力赢取信誉。

AllBetGaming声明:该文看法仅代表作者自己,与本平台无关。转载请注明:滨州信息港:.NET项目升级手记:可为空引用

网友评论

  • (*)

最新评论

  • 伸博开户官网 2020-05-10 00:07:47 回复

    www.66rfd.com(www.jlscbqtcl.com)是Sunbet 申博的官方网站。www.66rfd.com提供申博开户(sunbet开户)、SunbetAPP下载、Sunbet代理合作等业务。有没有其他推文

    1
    • ALLBET官网官方注册 2020-06-02 23:26:57 回复

      @伸博开户官网 欧博官网欢迎进入欧博官网(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。留名,此文必火

站点信息

  • 文章总数:594
  • 页面总数:0
  • 分类总数:8
  • 标签总数:928
  • 评论总数:180
  • 浏览总数:4659