这有点是一个开放式的问题,但我正试图通过异常处理方面的优秀实践来提高我的技能,特别是在检查空值时。
我知道什么时候检查空值但是我不得不说有一半时间我没有,这对我很困扰。我知道除非你使用可以为空的int,否则不能将int设置为null。我知道字符串可以设置为空或空,因此您可以检查IsNullOrEmpty。
显然,在构造函数中,您还希望在那里添加显式检查。这是给定的。而且我认为你应该在将数组,通用对象或其他对象传入一个基本上可以设置为null的方法时检查null吗?
但是这里有更多的异常处理。例如,我不知道何时总是检查并在代码中明确地抛出空引用异常。如果我有传入的参数,通常它很直接,但总会有我问自己的情况,是否需要明确的空投?
我真的没有具体的例子,但想知道是否有一个很好的参考,真正讨论异常处理参考何时抛出它们(在方法,类中,你命名它)。
答案 0 :(得分:15)
你不应该抛出NullReferenceException
。如果它是一个null throw ArgumentNullException
的参数。
我更喜欢为public / protected方法的所有引用类型参数检查null。对于私有方法,如果您确定所有呼叫始终具有有效数据,则可以省略检查。
答案 1 :(得分:6)
除非您使用代码约定,否则我认为检查任何公共/受保护成员的参数是一种好习惯,并且明确记录它们是否可以为空。对于私有/内部方法,它变成了验证您自己的代码而不是其他人的问题......这是一个判断调用。
我有时会使用辅助扩展方法,所以我可以写:
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
(除了可能应对第三方之外)不良)。
当然,您是否允许空值的决定是完全不同的事情。这完全取决于具体情况。防止空值进入你的世界确实会让事情变得更容易,但同时空值本身也是有用的。
答案 2 :(得分:6)
我在何时检查空值的经验法则是:
空参数的早期通知(更接近错误点)比远离错误点的随机NullReferenceExceptions
要好得多。
您可以使用实用程序方法清理典型的if( arg == null ) throw new ArgumentNullException(...);
构造。您可能还希望在C#4.0中查看code contracts作为改进代码的方法。代码契约执行静态和运行时检查,这有助于即使在编译时也能识别问题。
通常,为方法编写前提条件是一项耗时(因此经常省略)的实践。但是,这种类型的防御性编码的好处是可能节省时间调试red herrings,因为您没有验证输入。
作为旁注,ReSharper是一个很好的工具,用于识别对在运行时可能为null的参数或本地成员的潜在访问。
答案 3 :(得分:1)
越早越好。你越早捕获(无效)null,你就越不可能在某个关键过程中抛出。另一件需要考虑的事情是使用您的属性(setter)来集中验证。我经常在构造函数中引用我的属性,因此我可以很好地重用该验证。
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;
}
}
答案 4 :(得分:0)
取决于您的方法类型/ api / library / framework。我认为私有方法没问题,他们不检查空值,除非它们是一种断言方法。
如果您使用“非null”测试防御并乱丢您的代码 - 测试或“if” - 陈述您的代码将无法读取。
通过提交错误/空/空参数来定义客户端可能弄乱代码的区域。如果你知道在哪里,你可以画出在哪里进行空检查。在你的api入口点就像现实生活中的安全工作一样。
想象一下,每一分钟都会为每部电影都会在电影院里出示你的票而烦恼。
答案 5 :(得分:0)
我更喜欢使用静态模板方法来检查输入约束。这种情况的一般格式如下:
static class Check {
public static T NotNull(T arg) {
if( arg == null ) throw new ArgumentNullException();
}
}
使用它的好处是你的方法或构造函数现在可以用Check.NotNull()作为示例包装第一次使用参数:
this.instanceMember = Check.NotNull(myArgument);
当我到达.Net 4时,我可能会转换为代码合同,但在此之前这是有效的。顺便说一下,您可以在以下网址找到我更完整的Check类定义: