浅谈C#9.0新特性之参数非空检查简化

 更新时间:2020年11月3日 15:20  点击:2110

参数非空检查是缩写类库很常见的操作,在一个方法中要求参数不能为空,否则抛出相应的异常。比如:

public static string HashPassword(string password)
{
  if(password is null)
  {
    throw new ArgumentNullException(nameof(password));
  }
  ...
}

当异常发生时,调用者很容易知道是什么问题。如果不加这个检查,可能就会由系统抛出未将对象引用为实例之类的错误,这不利于调用者诊断错误。

由于这个场景太常见了,于是我经常在我的项目中通过一个辅助类来做此类检查。这个类用来检查方法参数,所以命名为 Guard,主要代码如下:

public static class Guard
{
  public static void NotNull(object param, string paramName)
  {
    if (param is null)
    {
      throw new ArgumentNullException(paramName);
    }
  }

  public static void NotNullOrEmpty(string param, string paramName)
  {
    NotNull(param, paramName);
    if (param == string.Empty)
    {
      throw new ArgumentException($"The string can not be empty.", paramName);
    }
  }

  public static void NotNullOrEmpty<T>(IEnumerable<T> param, string paramName)
  {
    NotNull(param, paramName);
    if (param.Count() == 0)
    {
      throw new ArgumentException("The collection can not be empty.", paramName);
    }
  }
  ...
}

这个类包含了三个常见的非空检查,包括 null、空字符串、空集合的检查。使用示例:

public static string HashPassword(string password)
{
  Guard.NotNull(password, nameof(password));
  ...
}

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
  this IEnumerable<TSource> source,
  Func<TSource, TKey> keySelector)
{
  Guard.NotNullOrEmpty(source, nameof(source));
  ...
}

介于这种非空检查极其常见,C# 9.0 对此做了简化,增加了操作符‘!',放在参数名后面,表示此参数不接受 null 值。使用方式如下:

public static string HashPassword(string password!)
{
  ...
}

简化了很多有木有。这个提案已经纳入 C# 9.0 的特性中,但目前(2020-06-13)还没有完成开发。

这个特性只支持非 null 检查,其它参数检查场景还是不够用的,我还是会通过辅助类来进行像空字符串、空集合的检查。

这个特性在写公共类库的时候很有用,但我想大多数人在写业务逻辑代码的时候可能用不到这个特性,一般会封自己的参数检查机制。比如,我在项目中,对于上层 API 开发,我通过封装一个辅助类(ApiGuard)来对对参数进行检查,如果参数不通过,则抛出相应的业务异常,而不是 ArgumentNullException。比如下面的一段截取自我的 GeekGist 小项目的代码:

public static class ApiGuard
{
  public static void EnsureNotNull(object param, string paramName)
  {
    if (param == null) throw new BadRequestException($"{paramName} can not be null.");
  }

  public static void EnsureNotEmpty<T>(IEnumerable<T> collection, string paramName)
  {
    if (collection == null || collection.Count() == 0)
      throw new BadRequestException($"{paramName} can not be null or empty.");
  }

  public static void EnsureExist(object value, string message = "Not found")
  {
    if (value == null) throw new BadRequestException(message);
  }

  public static void EnsureNotExist(object value, string message = "Already existed")
  {
    if (value != null) throw new BadRequestException(message);
  }
  ...
}

使用示例:

public async Task UpdateAsync(long id, BookUpdateDto dto)
{
  ApiGuard.EnsureNotNull(dto, nameof(dto));
  ApiGuard.EnsureNotEmpty(dto.TagValues, nameof(dto.TagValues));

  var book = await DbSet
    .Include(x => x.BookTags)
    .FirstOrDefaultAsync(x => x.Id == id);
  ApiGuard.EnsureExist(book);

  Mapper.Map(dto, book);

  ...
}

ApiGuard 的好处是,当 API 接口接到不合要求的参数时,可以自定义响应返回内容。比如,增加一个 Filter 或中间件用来全局捕获业务代码异常,根据不同的异常返回给前端不同的状态码和消息提示:

private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
  ApiResult result;
  if (exception is BadRequestException)
  {
    result = ApiResult.Error(exception.Message, 400);
  }
  else if (exception is NotFoundException)
  {
    message = string.IsNullOrEmpty(message) ? "Not Found" : message;
    result = ApiResult.Error(message, 404);
  }
  else if (exception is UnauthorizedAccessException)
  {
    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

[!--infotagslink--]

相关文章

  • Nest.js参数校验和自定义返回数据格式详解

    这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
  • 解决Springboot get请求是参数过长的情况

    这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
  • PHP中empty和isset对于参数结构的判断及empty()和isset()的区别

    废话不多说了,直接给大家贴代码了。<&#63;php class test{} $a1 = null; $a2 = ""; //$a3 = $a4 = 0; $a5 = '0'; $a6 = false; $a7 = array(); //var $a8; $a9 = new test(); for ($i=1; $i <=9 ; $i++) {...2015-11-24
  • java正则表达式判断前端参数修改表中另一个字段的值

    这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
  • mysql配置模板(my-*.cnf)参数详细说明

    mysql安装成功后有几个默认的配置模板,列表如下: my-huge.cnf : 用于高端产品服务器,包括1到2GB RAM,主要运行mysql my-innodb-heavy-4G.ini : 用于只有innodb的安装,最多有4GB RAM,支持大的查询和低流量 my-large.cnf : 用于...2015-03-15
  • 详解C#泛型的类型参数约束

    这篇文章主要介绍了C#泛型的类型参数约束的相关资料,文中讲解非常细致,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...2020-07-31
  • C#中out参数、ref参数与值参数的用法及区别

    这篇文章主要给大家介绍了关于C#中out参数、ref参数与值参数的用法及区别的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • Vue 组件复用多次自定义参数操作

    这篇文章主要介绍了Vue 组件复用多次自定义参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27
  • Java线程池中的各个参数如何合理设置

    这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
  • 详解Java后端优雅验证参数合法性

    这篇文章主要介绍了详解Java后端优雅验证参数合法性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18
  • 处理@PathVariable注解允许参数为空、允许不传参数的问题

    这篇文章主要介绍了处理@PathVariable注解允许参数为空、允许不传参数的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-23
  • vue+axios全局添加请求头和参数操作

    这篇文章主要介绍了vue+axios全局添加请求头和参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-24
  • SpringBoot接口接收json参数解析

    这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
  • pytorch 实现冻结部分参数训练另一部分

    这篇文章主要介绍了pytorch 实现冻结部分参数训练另一部分,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-27
  • C#向线程中传递多个参数的解决方法(两种)

    这篇文章主要介绍了C#向线程中传递多个参数的解决方法(两种)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • spring cloud gateway中如何读取请求参数

    这篇文章主要介绍了spring cloud gateway中如何读取请求参数的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-15
  • 使用JavaScript获取URL中的参数(两种方法)

    这篇文章主要介绍了使用JavaScript获取URL中的参数(两种方法)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2016-11-22
  • Vue中 axios delete请求参数操作

    这篇文章主要介绍了Vue中 axios delete请求参数操作,具有很好的参考价值,希望对大家有所 帮助。一起跟随小编过来看看吧...2020-08-26
  • SpringMvc自动装箱及GET请求参数原理解析

    这篇文章主要介绍了SpringMvc自动装箱及GET请求参数原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-19
  • 基于MyBatis的parameterType传入参数类型

    这篇文章主要介绍了基于MyBatis的parameterType传入参数类型,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-29