.net get set 初始化_.NET项目升级:可为空引用

(给DotNet加星标,提升.Net技能)

转自:波多尔斯基cnblogs.com/podolski/p/12692888.html

前言

C#8引入了新特性:可为空引用

https://docs.microsoft.com/zh-cn/dotnet/csharp/nullable-references

这个功能个人觉得挺好的,能够非常明确的表现程序设计者的意图,编译器能够进行检查,尽最大可能减小NullReferenceException错误。

如果是新项目,那么上手很简单,一点点搭建起来,遇山开山,遇河渡河。但是对于我这种手头上的项目大多都是以前创建的情况,就要稍微做那边么一点操作了。

要看完整说明,请查看开头的那个链接。

准备

首先评估一下几个条件:

1、项目可以基于.NET Core 3.0及以上编译。如果不行,那么就请直接右上角点×。

2、是不是大多数的变量都需要null引用?如果是的话,个人觉得不值得费劲了。

操作

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

689e747789672e3d0732004101b35587.png

1、启用Nullable(可为空引用类型)

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

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

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

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

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

2、修改代码

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

b750dd35a89296501d1f2dbd2dd15f4f.png

实体类

[DataContract]
[Table("recordinfo")]
public class RecordInfo : InfoBase
{
///
/// 记录ID
///
[DataMember]
[Key]
public string RecordNum { get; set; }

///
/// 车辆RFID号码
///
[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
{//整个类型会提示Data未能初始化,ErrorMsg未能初始化。public ReturnData(){ }public ReturnData(T data) => Data = data;public ReturnData(string error) => ErrorMsg = error;/// /// 页面数据/// public T Data { get; set; }public string ErrorMsg { get; set; }
}

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

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

public class ReturnData where T: class
{public ReturnData(){ }public ReturnData(T data) => Data = data;public ReturnData(string error) => ErrorMsg = error;/// /// 页面数据/// 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);//提示dbset可能为nullvar 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);//判断dbset可以解决问题。if (dbset == null) throw new ArgumentNullException("dbset");var res = await dbset.FindAsync(value);

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

总结

最后消除了所有的警告,改造结束。

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

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

推荐阅读  点击标题可跳转.NET Core 3.1运行Docke下实现负载均衡ASP.NET Core深入理解kestrel的应用.NET Core下的开源分布式任务调度系统

看完本文有收获?请转发分享给更多人

关注「DotNet」加星标,提升.Net技能 

eb46f6b41646b1b9d627a8fa4f398edf.png

好文章,我在看❤️

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/470416.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用GDB排查Python程序故障

某Team在用Python开发一些代码,涉及子进程以及设法消除僵尸进程的需求。实践中他们碰上Python程序非预期退出的现象。最初他们决定用GDB调试Python解释器,查看exit()的源头。我听了之后,觉得这个问题应该用别的调试思路。帮他们排查这次程序故…

解决后端返回数据中的大数字问题(使用第三方包json-bigint )

JavaScript 能够准确表示的整数范围在-2^53到2^53之间(不含两个端点),超过这个范围,无法精确表示这个值,这使得 JavaScript 不适合进行科学和金融方面的精确计算。 Math.pow(2, 53) // 90071992547409929007199254740…

java 静态代码块_关于Java你不知道的那些事之代码块

前言普通代码块:在方法或语句中出现的{},就被称为代码块静态代码块:静态代码块有且仅加载一次,也就是在这个类被加载至内存的时候普通代码块和一般语句执行顺序由他们在代码中出现的次序决定,先出现先执行代码一/**对于…

Vue项目开发过程中解决跨域问题(vue.config.js结合axios)

一、问题描述 在本地开发过程中,调用后端提供的接口获取数据将获取的数据渲染到页面中,但是浏览器报错: // 控制台报错信息 Access to XMLHttpRequest at http://x.x.x.x/app/v1_0/user/followings from origin http://localhost:8080 has…

WebSocket实现实时通信

WebSocket 是一种数据通信协议,也是用于客户端和服务端数据通信,类似于我们常见的 http 既然有 http,为啥还要 WebSocket http 通信是单向的 请求 响应 没有请求也就没有响应 初次接触 WebSocket 的人,都会问同样的问题&#xf…

使用socket.io搭建一个实时聊天机器人

一、安装socket.io npm i socket.io --save二、使用 第一种:服务端使用原生node // 创建http服务器 const http require(http) var fs require(fs) const app http.createServer()app.on(request, (req, res) > {fs.readFile(__dirname /index.html, funct…

真随机和伪随机区别_用骰子DIY真随机助记词 | 火星号精选

免责声明:本文旨在传递更多市场信息,不构成任何投资建议。文章仅代表作者观点,不代表火星财经官方立场。小编:记得关注哦

EasyDarwin开源流媒体服务器性能瓶颈分析及优化方案设计

EasyDarwin现有架构介绍 EasyDarwin的现有架构对网络事件的处理是这样的,每一个Socket连接在EasyDarwin内部的对应存在形式就是一个Session,不论是RTSP服务对应的RTSPSession,还是HTTP服务对应的HTTPSession,都是一个继承自Task类…

Vue 中的组件缓存

一、介绍 先来看一个问题? 从首页的区块链模块切换到文章详情页面,再从文章详情页面回到首页,我们发现首页重新渲染原来的状态没有了,又回到了推荐模块。 首先,这是正常的状态,并非问题,路由…

SQLlite 分页

如果我要去11-20的Account表的数据 Select * From Account Limit 9 Offset 10; 以上语句表示从Account表获取数据,跳过10行,取9行 嗯,我觉得这个特性足够让很多的web中型网站使用这个了。 也可以这样写 select * from account limit10,9和上面…

thief book怎么用_战略管理工具箱--30个好用的战略管理好工具

-原创转载请告知-十年多年前,在上海做咨询的时候,曾经在书店买了一本《战略管理工具箱》的Poket小书,一直看一直看,里面包含常用的战略管理工具(30个),虽然不用都用上,用其中几个常用…

Vue中使用axios的响应拦截器处理请求失败的情况(处理token过期问题)以及 登录成功跳转回原来页面问题

参考axios官方文档 // 响应拦截器 // Add a response interceptor request.interceptors.response.use(// 在2xx范围内的任何状态代码都会触发此函数,这里主要用于处理响应数据response > {return response},// 任何超出2xx范围的状态码都会触发此函数&#xff0…

cocoapods 命令

1.使用CocoaPods a 新建一个项目,名字cocoapods b 终端中,cd到项目总目录(直接拖过来) [objc] copy? cd /Users/pengjian/Desktop/cocoapodsc 建立Podfile(配置文件) 接着上一步,终端输入 v…

Vue项目中使用 路由导航守卫 处理页面的访问权限

参考Vue-Router官方文档 Vue-Router导航守卫 效果展示 1、给需要登录状态才能访问的页面路由对象的 meta 中添加配置属性 { // 小智同学name: user-chat,path: /user/chat,component: () > import(/views/user-chat),meta: { requiresAuth: true } },2、通过路由拦截器…

失败,因为你其实太过傲慢

因为你太过傲慢,不肯放低姿态去向他人学习,勤加练习,所以失败。转载于:https://www.cnblogs.com/panie2015/p/5667464.html

Uniapp学习笔记(数据展示、数据循环、条件编译、计算属性、组件的使用、组件插槽、生命周期)

1.项目准备 1.1开发方式 uni-app为我们提供2种开发方式: 使用DCloud公司提供HBuilderX工具来快速开发; 使用脚手架来快速开发(我们这次项目使用此方式); 1.2脚手架搭建项目 全局安装,如果你以前安装过…

word图片嵌入式为何只能看到一部分_Word排版的正确姿势!(Word论文排版教学)...

Hello,最近正值着手写毕业论文的初期,趁着这个时间点,我做了一个简易的,简单的,0基础的Word论文排版教学,帮助你在撰写论文的时候不再花费大量的时间浪费在调整格式里。初次做视频,难免有错误&a…

云计算三种服务模式SaaS、PaaS和IaaS及其之间关系(顺带CaaS、MaaS)

云计算架构图 很明显,这五者之间主要的区别在于第一个单词,而aaS都是as-a-service(即服务)的意思,这五个模式都是近年来兴起的,且这五者都是云计算的落地产品,所以我们先来了解一下云计算是什么…

uni-ui介绍uni-api

一、uni-ui介绍 安装 二、uni-api 解决uni-app中的跨域问题: "h5" : {"router" : {"mode" : "hash"},"devServer": {"https": false,"proxy": {"/web": {"target": …

一、uniapp项目(封装异步请求、moment.js时间处理、封装手势滑动组件、下载图片到本地)

一、封装异步请求: 1. 为什么要封装? 2. 封装的思路 export default (params) > {// 显示加载中uni.showLoading({title: "加载中"})return new Promise((resolve, reject) > {wx.request({...params,success(res) {resolve(res)},fail…