如果一个参数为null,最佳做法是什么?

Gal*_*you 18 .net c# argument-validation

在验证方法的输入时,我用来检查参数是否为null,如果是,我抛出一个ArgumentNullException.我为列表中的每个参数执行此操作,因此我最终得到如下代码:

 public User CreateUser(string userName, string password, 
                            string Email, string emailAlerts, 
                            string channelDescription)
    {

        if (string.IsNullOrEmpty(userName))
            throw new ArgumentNullException("Username can't be null");

        if (string.IsNullOrEmpty(Email))
            throw new ArgumentNullException("Email can't be null");
       //etc, etc, etc
    }
Run Code Online (Sandbox Code Playgroud)

这个可以吗?我为什么要这样做?如果我只是将所有检查分组并返回空值而不是抛出异常,那会没关系吗?解决这种情况的最佳做法是什么?

PS:我想改变这一点,因为使用长方法,这样做非常繁琐.
想法?

Lou*_*nco 17

用这样的东西制作一个ArgChecker类

  ArgChecker.ThrowOnStringNullOrEmpty(userName, "Username");
Run Code Online (Sandbox Code Playgroud)

其中ThrowOnStringNullOrEmpty是

  public static void ThrowOnStringNullOrEmpty(string arg, string name)
  {
      if (string.IsNullOrEmpty(arg))
        throw new ArgumentNullException(name + " can't be null");
  }
Run Code Online (Sandbox Code Playgroud)

您还可以尝试使用params arg处理参数列表,例如:

  public static void ThrowOnAnyStringNullOrEmpty(params string[] argAndNames)
  {
       for (int i = 0; i < argAndName.Length; i+=2) {
          ThrowOnStringNullOrEmpty(argAndNames[i], argAndNames[i+1]);
       }
  }
Run Code Online (Sandbox Code Playgroud)

并像这样打电话

  ArgChecker.ThrowOnAnyStringNullOrEmpty(userName, "Username", Email, "email");
Run Code Online (Sandbox Code Playgroud)

  • 我唯一的问题是ArgumentNullException可能不适用于空String,因为它不是null。也许其他形式的无效或非法论证例外会更好。 (2认同)

Mat*_*lls 17

我使用的方法和我可能从NHibernate源代码中获取的方法是创建一个静态类Guard,使用如下:

public void Foo(object arg1, string arg2, int arg3)
{
    Guard.ArgumentNotNull(arg1, "arg1");
    Guard.ArgumentNotNullOrEmpty(arg2, "arg2");
    Guard.ArgumentGreaterThan(arg3, "arg3", 0);
    //etc.
}

public static class Guard
{
    public static void ArgumentNotNull(object argument, string parameterName)
    {
        if (parameterName == null)
            throw new ArgumentNullException("parameterName");

        if (argument == null)
            throw new ArgumentNullException(parameterName);
    }
    //etc.
}
Run Code Online (Sandbox Code Playgroud)

这在方法开始时减少了很多糠,并且表现良好.


Wel*_*bog 9

您应该考虑方法,需要做什么以及使用什么数据.如果空值表示实际故障条件,请使用异常.如果可以接受空值,则接受它们.

考虑从合同设计的原则,特别是你的功能的前提条件,并规范一种强制执行的方式(Matt和Lou都在他们的答案中提出建议,所以我不需要详细说明).

另一个需要考虑的重要事项是方法签名的大小.如果你的方法有很多参数,这可能意味着你有很糟糕的抽象.如果在集合对象中将参数组合在一起并将这些对象用作参数,则可以减少必须进行的参数检查的数量.您可以将参数检查移动到这些对象,而不必在使用它们的每个函数中检查它们.

因此,不是将十个相关参数传递给每个函数,而是找出每个函数中使用的少数参数并将它们打包在一个对象中,并在该对象中包含验证参数的方法.如果需要更新关于一个参数的规则,这具有易于改变的附加优点.

  • 在_Clean Code_中,罗伯特·马丁认为,不是7,而是零 - 这是正确的,零 - 理想的参数数量,其中一个紧随其后.在这里使用Wellbog的好主意,你应该能够更接近这些理想.当你试图推动这些限制时,它非常有趣,有时非常好; 你会惊讶于它的可能性以及你对代码的喜爱程度. (2认同)

Sha*_*e K 5

对于我们中的C#3.0开发人员来说,封装此null检查的一种很好的方法是在扩展方法中.

public void Foo(string arg1, int? arg2)
{
  arg1.ThrowOnNull();
  arg2.ThrowOnNull();
}

public static class extensions
{
    public static void ThrowOnNull<T>(this T argument) where T : class
    {
        if(argument == null) throw new ArgumentNullException();
    } 
}
Run Code Online (Sandbox Code Playgroud)

如果你想要你可以总是重载它来获取一个参数名称.

  • 我不确定我是否喜欢显然在null对象上调用的方法,尽管我很欣赏这对于扩展方法是合法的.在'syntactic dissonance'下的文件. (3认同)