ArgumentException的正确用法

本文关键字:用法 ArgumentException | 更新日期: 2023-09-27 17:57:27

根据我所看到的,ArgumentExceptions通常是这样使用的:

public void UpdateUser(User user)
{
    if (user == null) throw new ArgumentException("user");
    // etc...
}

但是如果我有这样的东西呢:

public void UpdateUser(int idOfUser)
{
    var user = GetUserById(idOfUser);
    if (user == null) throw new ArgumentException("idOfUser");
    // etc...
}

那还是ArgumentException吗?

ArgumentException的正确用法

第一个

if (user == null) throw new ArgumentException("user");

应该是

if (user == null) throw new ArgumentNullException("user");

如果可能的话,你不应该直接扔ArgumentException

ArgumentException的主要派生类是ArgumentNullExceptionArgumentOutOfRangeException。应该使用这些派生类而不是ArgumentException,除非这两个派生类都不可接受。

对于第二个示例,我应该为数据库查找抛出KeyNotFoundException吗?他们建议(在评论中)

if (user == null) throw new ObjectNotFoundException();

其定义见System.Data:System.Data.ObjectNotFoundException

顾名思义,ArgumentException是参数的一个例外。这意味着这个论点在某种程度上本质上是错误的。

一般形式为:

public void SomeMethod(SomeType arg)
{
  if(!TestArgValid(arg))
    throw new ArgumentException("arg"); //Or more specific is possible
                                        //e.g. ArgumentNullException
    /* Actually do stuff */
}

如果GetUserById失败的唯一可能方式是idOfUser的值存在固有错误,那么在实践中以下两种情况都是相同的:

public void UpdateUser(int idOfUser)
{
  if(!TestValid(idOfUser))
    throw new ArgumentException("idOfUser");
  var user = GetUserById(idOfUser);
  // Do stuff with user
}
public void UpdateUser(int idOfUser)
{
  var user = GetUserById(idOfUser);
  if(user == null)
    throw new ArgumentException("idOfUser");
  // Do stuff with user
}

如果由于某种原因,在事后测试user比在事前测试idOfUser更快或更少浪费一些资源,调用GetUserById没有副作用,且差异确实很重要,则第二个版本可能是对第一个版本的合理优化。

但只有当上面的所有if都成立时,这才成立,这是一种检测无效参数的奇怪方法,它有一些特定的优势,我们可以通过将这种奇怪之处隐藏起来,从方法的封装中受益。

很可能存在一个有效的idOfUser,但没有对应的user,在这种情况下,它肯定不是一个参数例外。