假设我有一个方法将某种对象作为参数.现在说如果这个方法传递一个null参数,那就是一个致命的错误,应该抛出一个异常.编写这样的代码对我来说是否值得(请记住这是一个简单的例子):
void someMethod(SomeClass x) { if (x == null){ throw new ArgumentNullException("someMethod received a null argument!"); } x.doSomething(); }
或者,当它调用x.doSomething()时,依赖它抛出NullException是否安全?
其次,假设someMethod是一个构造函数,在调用另一个方法之前不会使用x.我应该立即抛出异常还是等到需要x然后抛出异常?
我喜欢ArgumentNullException
过NullReferenceException
,不是检查参数将提供.通常,我的首选是在尝试在潜在的null对象上调用方法之前始终检查null.
如果该方法是构造函数,那么它将取决于几个不同的因素:是否还有该属性的公共setter以及该对象实际使用的可能性.如果有一个公共setter,那么不通过构造函数提供有效的实例是合理的,不应该导致异常.
如果没有公共setter并且可以在不引用注入对象的情况下使用包含对象,则可能需要推迟检查/异常,直到尝试使用它为止.我认为一般情况下,注入的对象对于实例的运行至关重要,因此ArgumentNull异常是完全合理的,因为没有它,实例就无法运行.
我总是遵循快速失败的做法.如果您的方法依赖于X并且您理解X可能以null传递,则检查它并立即引发异常而不是延长故障点.
2016年更新:
现实世界的例子.我强烈建议使用Jetbrains Annotations.
[Pure] public static object Call([NotNull] Type declaringType, [NotNull] string methodName, [CanBeNull] object instance) { if (declaringType == null) throw new ArgumentNullException(nameof(declaringType)); if (methodName == null) throw new ArgumentNullException(nameof(methodName));
C#6为nameof
操作员提供了大大改进的防护声明.
出于以下原因,我更喜欢显式异常:
如果该方法具有多个SomeClass参数,则可以让您有机会说出它是哪一个(其他所有内容都在调用堆栈中可用).
如果你在引用x之前做了一些可能有副作用的事情怎么办?
我同意快速失败的想法 - 然而,明智的是,为什么快速失败是切实可行的.考虑这个例子:
void someMethod(SomeClass x) { x.Property.doSomething(); }
如果你依靠NullReferenceException
告诉你出了什么问题,你怎么知道什么是空的?堆栈跟踪只会为您提供行号,而不是哪个引用为空.在这个例子中,x
或者x.Property
两者都可以为空并且没有事先通过激进检查快速失败,你将不知道它是什么.
我更喜欢使用显式ArgumentNullException进行参数检查.
查看元数据:
// // Summary: // Initializes a new instance of the System.ArgumentNullException class with // the name of the parameter that causes this exception. // // Parameters: // paramName: // The name of the parameter that caused the exception. public ArgumentNullException(string paramName);
你可以看到,字符串应该是参数的名称,即null,因此给开发人员一个关于出错的提示.
最好早点而不是稍后抛出ArgumentNullException.如果你抛出它,你可以提供有关问题的更多有用信息,而不是NullReferenceException.
如果您希望输入不为null,则应显式抛出ArgumentNullException.您可能希望编写一个名为Guard的类,为此提供帮助方法.所以你的代码将是:
void someMethod(SomeClass x, SomeClass y) { Guard.NotNull(x,"x","someMethod received a null x argument!"); Guard.NotNull(y,"y","someMethod received a null y argument!"); x.doSomething(); y.doSomething(); }
NonNull方法将执行nullity检查并抛出NullArgumentException,并在调用中指定错误消息.