C# 何时检查空值

C# 何时检查空值,c#,exception-handling,C#,Exception Handling,这是一个开放式的问题,但我正试图通过良好的异常处理实践来提高我的技能,特别是在一般情况下检查空值的时候 我知道什么时候检查空值,但我不得不说一半时间我不知道,这让我很烦恼。我知道除非使用可为null的int,否则int不能设置为null。我知道字符串可以设置为null或空,因此可以检查IsNullOrEmpty 显然,在构造函数中,您也希望在其中添加显式检查。这是必然的。我认为在将数组、泛型对象或其他对象传递到可以设置为null的方法中时,应该检查null,基本上正确吗 但是这里有更多的异常处理

这是一个开放式的问题,但我正试图通过良好的异常处理实践来提高我的技能,特别是在一般情况下检查空值的时候

我知道什么时候检查空值,但我不得不说一半时间我不知道,这让我很烦恼。我知道除非使用可为null的int,否则int不能设置为null。我知道字符串可以设置为null或空,因此可以检查IsNullOrEmpty

显然,在构造函数中,您也希望在其中添加显式检查。这是必然的。我认为在将数组、泛型对象或其他对象传递到可以设置为null的方法中时,应该检查null,基本上正确吗

但是这里有更多的异常处理。例如,我不知道何时总是在代码中明确地检查并抛出null ref异常。如果我有传入的参数,通常是非常直接的,但总有一些情况下我会问自己,是否需要显式的null抛出


我并没有具体的例子,但我想知道是否有一个很好的参考文献,真正涉及到何时抛出异常处理(在方法、类内部,你可以这么说)。

你不应该抛出
NullReferenceException
。如果参数为null,则改为抛出
ArgumentNullException


我更喜欢检查public/protected方法的所有引用类型参数是否为null。对于私有方法,如果您确定所有调用始终具有有效数据,则可以省略检查

除非您使用的是代码契约,否则最好检查任何公共/受保护成员的参数,并明确记录它们是否可以为null。对于私有/内部方法,验证您自己的代码而不是其他人的。。。在这一点上,这是一个判断

我有时会为此使用助手扩展方法,因此我可以编写:

public void Foo(string x, string y, string z)
{
    x.ThrowIfNull("x");
    y.ThrowIfNull("y");
    // Don't check z - it's allowed to be null
    // Method body here
}
ThrowIfNull
将抛出具有适当名称的
ArgumentNullException

通过在进行任何其他调用之前进行显式检查,您知道如果抛出异常,则不会发生任何其他情况,从而不会出现损坏状态

我承认我会忽略这样的检查,因为我确信第一次调用会执行相同的检查——例如,如果是一个过载负载在另一个过载负载上

对于代码契约,我会写:

public void Foo(string x, string y, string z)
{
    Contract.Requires(x != null);
    Contract.Requires(y != null);

    // Rest of method here
}
这将抛出一个
ContractException
,而不是
ArgumentNullException
,但所有信息仍然存在,并且无论如何都不应该有人显式捕获
ArgumentNullException
(可能是为了应对第三方不良行为)


当然,是否允许空值的决定是完全不同的。这完全取决于形势。防止空值进入您的世界确实使某些事情变得更容易,但同时空值本身也很有用。

我的经验法则是:

  • 始终检查传递给任何类的公共/受保护方法的参数
  • 始终检查构造函数和初始化方法的参数
  • 始终检查索引器或属性设置器中的参数
  • 始终检查作为接口实现的方法的参数
  • 对于多个重载,尝试将所有参数预条件放在其他重载委托给的单个方法中
早期通知空参数(接近错误点)比在远离错误点的地方发生的随机
NullReferenceExceptions
要好得多

如果(arg==null)抛出新的ArgumentNullException(…),可以使用实用程序方法清理典型的
构造。您可能还希望研究C#4.0中的代码,以改进代码。代码契约执行静态和运行时检查,即使在编译时也可以帮助识别问题

一般来说,编写方法的前提条件是一种耗时的做法(因此经常被忽略)。但是,这种防御性编码的好处在于,由于您没有验证输入,因此可能会节省数小时的调试时间


作为旁注,是一个很好的工具,用于识别对参数或本地成员的潜在访问,这些参数或本地成员在运行时可能为空。

越早越好。你越快抓住(无效)空,你就越不可能在某个关键过程中抛出。另一个需要考虑的事情是使用您的属性(SETTES)集中验证。我经常在构造函数中引用我的属性,因此我在验证中得到了很好的重用

class A
{
  private string _Name
  public string Name
  {
    get { return _Name; }
    set 
    {
      if (value == null)
         throw new ArgumentNullException("Name");
      _Name = value;
    }
  }

  public A(string name)
  {
     //Note the use of property with built in validation
     Name = name;
  }
}

取决于方法/api/库/框架的类型。我认为私有方法可以不检查空值,除非它们是一种断言方法

如果你编写防御性的程序,并且在代码中乱扔“NOTNULL”-测试或“If”-语句,那么你的代码将无法读取

定义客户端通过提交错误的/空的/空的参数而使代码混乱的区域。如果你知道在哪里,你可以画一条线在哪里做你的空检查。在api入口点执行此操作,就像在现实生活中安全工作一样


想象一下,如果你每分钟都在电影院里出示门票,那么每部电影都会很糟糕。

我更喜欢使用静态模板方法来检查输入约束。一般的格式如下:

static class Check {
    public static T NotNull(T arg) {
        if( arg == null ) throw new ArgumentNullException();
    }
}
使用它的好处是,您的方法或构造函数现在可以使用Check.NotNull()包装参数的第一次使用,如下所示:

this.instanceMember = Check.NotNull(myArgument);
当我使用.NET4时,我可能会转换为代码契约,但在此之前,这是可行的。顺便说一句,您可以在以下url找到我使用的检查类的更完整定义:


值得一提的是,.NET代码契约的一大好处是