浅谈C#9.0新特性之参数非空检查简化
参数非空检查是缩写类库很常见的操作,在一个方法中要求参数不能为空,否则抛出相应的异常。比如:
publicstaticstringHashPassword(stringpassword)
{
if(passwordisnull)
{
thrownewArgumentNullException(nameof(password));
}
...
}
当异常发生时,调用者很容易知道是什么问题。如果不加这个检查,可能就会由系统抛出未将对象引用为实例之类的错误,这不利于调用者诊断错误。
由于这个场景太常见了,于是我经常在我的项目中通过一个辅助类来做此类检查。这个类用来检查方法参数,所以命名为Guard,主要代码如下:
publicstaticclassGuard
{
publicstaticvoidNotNull(objectparam,stringparamName)
{
if(paramisnull)
{
thrownewArgumentNullException(paramName);
}
}
publicstaticvoidNotNullOrEmpty(stringparam,stringparamName)
{
NotNull(param,paramName);
if(param==string.Empty)
{
thrownewArgumentException($"Thestringcannotbeempty.",paramName);
}
}
publicstaticvoidNotNullOrEmpty(IEnumerableparam,stringparamName)
{
NotNull(param,paramName);
if(param.Count()==0)
{
thrownewArgumentException("Thecollectioncannotbeempty.",paramName);
}
}
...
}
这个类包含了三个常见的非空检查,包括null、空字符串、空集合的检查。使用示例:
publicstaticstringHashPassword(stringpassword)
{
Guard.NotNull(password,nameof(password));
...
}
publicstaticIEnumerableDistinctBy(
thisIEnumerablesource,
FunckeySelector)
{
Guard.NotNullOrEmpty(source,nameof(source));
...
}
介于这种非空检查极其常见,C#9.0对此做了简化,增加了操作符‘!',放在参数名后面,表示此参数不接受null值。使用方式如下:
publicstaticstringHashPassword(stringpassword!)
{
...
}
简化了很多有木有。这个提案已经纳入C#9.0的特性中,但目前(2020-06-13)还没有完成开发。
这个特性只支持非null检查,其它参数检查场景还是不够用的,我还是会通过辅助类来进行像空字符串、空集合的检查。
这个特性在写公共类库的时候很有用,但我想大多数人在写业务逻辑代码的时候可能用不到这个特性,一般会封自己的参数检查机制。比如,我在项目中,对于上层API开发,我通过封装一个辅助类(ApiGuard)来对对参数进行检查,如果参数不通过,则抛出相应的业务异常,而不是ArgumentNullException。比如下面的一段截取自我的GeekGist小项目的代码:
publicstaticclassApiGuard
{
publicstaticvoidEnsureNotNull(objectparam,stringparamName)
{
if(param==null)thrownewBadRequestException($"{paramName}cannotbenull.");
}
publicstaticvoidEnsureNotEmpty(IEnumerablecollection,stringparamName)
{
if(collection==null||collection.Count()==0)
thrownewBadRequestException($"{paramName}cannotbenullorempty.");
}
publicstaticvoidEnsureExist(objectvalue,stringmessage="Notfound")
{
if(value==null)thrownewBadRequestException(message);
}
publicstaticvoidEnsureNotExist(objectvalue,stringmessage="Alreadyexisted")
{
if(value!=null)thrownewBadRequestException(message);
}
...
}
使用示例:
publicasyncTaskUpdateAsync(longid,BookUpdateDtodto)
{
ApiGuard.EnsureNotNull(dto,nameof(dto));
ApiGuard.EnsureNotEmpty(dto.TagValues,nameof(dto.TagValues));
varbook=awaitDbSet
.Include(x=>x.BookTags)
.FirstOrDefaultAsync(x=>x.Id==id);
ApiGuard.EnsureExist(book);
Mapper.Map(dto,book);
...
}
ApiGuard的好处是,当API接口接到不合要求的参数时,可以自定义响应返回内容。比如,增加一个Filter或中间件用来全局捕获业务代码异常,根据不同的异常返回给前端不同的状态码和消息提示:
privateTaskHandleExceptionAsync(HttpContextcontext,Exceptionexception)
{
ApiResultresult;
if(exceptionisBadRequestException)
{
result=ApiResult.Error(exception.Message,400);
}
elseif(exceptionisNotFoundException)
{
message=string.IsNullOrEmpty(message)?"NotFound":message;
result=ApiResult.Error(message,404);
}
elseif(exceptionisUnauthorizedAccessException)
{
message=string.IsNullOrEmpty(message)?"Unauthorized":message;
result=ApiResult.Error(message,401);
}
...
}
只是一个参数非空检查,在实际开发中却有不少的学问,所以学好了理论还要多实践才能更透彻的理解它。
到此这篇关于浅谈C#9.0新特性之参数非空检查简化的文章就介绍到这了,更多相关C#9.0参数非空检查内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
作者:王亮
出处:http://cnblogs.com/willick
联系:liam.wang@live.com