我习惯于检查方法的参数是否为null(然后继续抛出异常),我几乎不再考虑它了。 如果参数是引用类型,那就是:
if(arg == null)
throw new ArgumentNullException(nameof(arg));
但是,如果我要立即使用arg怎么办?我应该检查一下吗?我的意思是,如果我不这样做,无论如何,envinroment都会为我抛出(NullReferenceException)。
例如:
public int DoStuff(object o)
{
return o.GetHashCode();
}
我可以轻松地添加空检查:
public int DoStuff(object o)
{
if(o == null)
throw new ArgumentNullException(nameof(o));
return o.GetHashCode();
}
但是在这两种情况下都会抛出异常(在几乎完全相同的行中,出于调试目的)。唯一的区别是类型。
问题:在带有单引用类型参数的 public 方法上,如果我要立即使用参数 ,如果它是null
,我还应检查吗?
答案 0 :(得分:10)
我建议检查,因为你有两个异常类型:
NullReferenceException
- 出错了,您必须调试自己的例行程序 ArgumentNullException
- 参数为空,并且调用者是错误的(而不是您的代码,它会对正确做出反应)< / LI>
醇>
投掷ArgumentNullException
是一种合同:如果参数正确,我会做的事情:
// An exaggerated example
public int DoStuff(SomeObject o) {
if (o == null)
throw new ArgumentNullException(nameof(o));
else if (o.Disposed)
throw new ArgumentException(nameof(o), "o must not be disposed")
else if (o.Id > 100)
throw new ArgumentOutOfRangeException("Id ...", nameof(o));
// o meets the contract, we accept it and thus we guarantee the output
return o.SomeMethod();
}
这种验证对于 public ( protected )方法来说是典型的,因为它们暴露在外部世界并且可以面对任何争论;但是,在 private 方法的情况下,您可以省略合同:任何调用者都在实现该方法的类中。
答案 1 :(得分:0)
嗯,这取决于;) 这是我的看法,问题是(有点)主观。
IMO,如果代码抛出NullReferenceException,则意味着代码本身没有内部一致性。这是懒惰的表现,应该不惜一切代价避免。 如果方法抛出NullReferenceException,那就是方法的错误。
另一方面,另一方面,ArgumentNullException意味着该方法不能“做”它的东西&#34;如果参数为null。 调用者负责保证参数不为null,或者优雅地处理异常。底线:ArgumentNullException是一个契约,NullReferenceException是一个bug。
答案 2 :(得分:0)
我想如果你立即取消引用变量,你可以辩论任何一种方式,但我仍然更喜欢ArgumentNullException。 对于正在发生的事情,它更明确。该异常包含变量的名称为null,而NullReferenceException则不包含。
答案 3 :(得分:0)
我强烈建议您检查方法顶部的null
。
将其视为指定以下内容的“合同”:
为了执行此方法,此参数必须为非null。
执行空检查是很好的文档。您可以更进一步使用XML注释,例如
/// <summary>
///
/// </summary>
/// <param name="arg1"></param>
/// <exception cref="ArgumentNullException">If <paramref name="arg1"/> is NULL.</exception>
private static void Foo(object arg1)
{
}
答案 4 :(得分:0)
我会说这更多地取决于你如何处理错误,而不是如何处理它们。一个例子会有所帮助。想象一下,这是方法,而不是你拥有的方法:
public static int DoStuff(string o) {
return Int.Parse(o);
}
如果你有这个,那真的没关系。
public static void main(string[] args)
{
try {
Console.Write("Enter a number: ");
value = DoStuff(Console.ReadLine());
}
catch(Exception ex) {
Console.WriteLine("An exception was thrown. Contents: " + ex.ToString());
}
}
无论哪种方式,您的程序流程都是相同的。但如果你有以下内容:
public static void main(string[] args)
{
try {
int value = 0;
do {
try {
Console.Write("Enter a non-zero number to stop: ");
value = DoStuff(Console.ReadLine());
}
catch(ArgumentException ex) {
Console.WriteLine("Problem with input, try again. Exception message was: " + ex.Message);
continue; // Or just nothing, will still loop
}
} while(value == 0);
}
catch(Exception ex) {
Console.WriteLine("An exception was thrown. Contents: " + ex.ToString());
}
}
基本上,如果您的错误处理不关心它是哪种异常类型,那么它只是额外的代码,可能对您没有帮助。但是如果你以不同的方式处理特定的事情,那么测试并抛出更具体的异常类型可能是值得的。
但我同意上面的德米特里的帖子,公共方法比私人方法更重要。您对该方法的签名有点像合同。最好强制执行它。
答案 5 :(得分:0)
我认为你应该考虑一些不同的场景:
点(1)和(2)是关于异常安全。基本上,这表明无论您的输入如何,您的数据结构的状态应该是一致的。在大多数情况下,这可以通过简单的检查来解决;在更复杂的情况下,它可能涉及回滚或更复杂的机器。所以:
null
值,则不希望它使数据库陷入困境。现在,您可以通过简单地检查您的假设来解决null
值。如果参数为null
,则抛出ArgumentNullException
,因为这最能描述该场景。null
值的方法并且它不会影响你系统的其余部分,我通常会在某个地方发表评论并让大自然继续前进。 NullReferenceException
告诉了我关于这个bug的本质的充分信息。ArgumentNullException
)。而且,作为开发者,你不应该相信外面的大坏事,所以你应该检查。 Assertion
。断言通常以这样的方式实现,即它们不会以释放代码结束(或者至少对您的速度没有影响),会自动触发断点并且会使单元测试失败。它们也很容易识别,所以它们不会给你的代码增加过多的膨胀。总而言之,我不会在任何地方放置支票;他们倾向于使你的代码不可读和臃肿。也就是说,如果我要检查以确保异常安全,最好使用最能描述错误的异常。
答案 6 :(得分:-1)
跟随爱因斯坦 - “让事情变得尽可能简单,但并不简单”。没有一行代码,那些代码是否会做同样的事情?如果是这样,最好将其删除。