合作网站账号登录方式,浙江省建设厅网站张清云,制作微网站多少钱,网站免费网站的方法c# 8引入了新特性#xff1a;“可为空引用”#xff08;详情#xff09;#xff0c;这个功能个人觉得挺好的#xff0c;能够非常明确的表现程序设计者的意图#xff0c;编译器能够进行检查#xff0c;尽最大可能减小NullReferenceException错误。如果是新项目#xff0… c# 8引入了新特性“可为空引用”详情这个功能个人觉得挺好的能够非常明确的表现程序设计者的意图编译器能够进行检查尽最大可能减小NullReferenceException错误。如果是新项目那么上手很简单一点点搭建起来遇山开山遇河渡河。但是对于我这种手头上的项目大多都是以前创建的情况就要稍微做那边么一点操作了。要看完整说明请查看开头的那个链接。准备首先评估一下几个条件项目可以基于.NET CORE 3.0及以上编译。如果不行那么就请直接右上角点×。是不是大多数的变量都需要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类使用构造函数保证不为空。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 ReturnDataT
{//整个类型会提示Data未能初始化ErrorMsg未能初始化。public ReturnData(){ }public ReturnData(T data) Data data;public ReturnData(string error) ErrorMsg error;/// summary/// 页面数据/// /summarypublic T Data { get; set; }public string ErrorMsg { get; set; }
}
设计意图Data与ErrorMsg不同时为空也不同时有值。基于设计可以做如下修改。注意添加了class约束。public class ReturnDataTwhere T: class
{public ReturnData(){ }public ReturnData(T data) Data data;public ReturnData(string error) ErrorMsg error;/// summary/// 页面数据/// /summarypublic 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 DbSetT);
//提示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 DbSetT);
//判断dbset可以解决问题。
if (dbset null) throw new ArgumentNullException(dbset);
var res await dbset.FindAsync(value);
注意将as替换为强制转换并不能消除警告。总结最后消除了所有的警告改造结束。这个新的语言特性可以帮助我们发现一些潜在的bug点帮助我们养成良好的编程习惯也便于我们告诉其他人我们的设计意图。编译器能帮我们做的工作就没必要自己再费劲做了懒的不行我得歇会儿。