抛出ArgumentNullException

Jas*_*ker 59 .net c# exception-handling exception

假设我有一个方法将某种对象作为参数.现在说如果这个方法传递一个null参数,那就是一个致命的错误,应该抛出一个异常.编写这样的代码对我来说是否值得(请记住这是一个简单的例子):

void someMethod(SomeClass x)
{
    if (x == null){
        throw new ArgumentNullException("someMethod received a null argument!");
    }

    x.doSomething();
}
Run Code Online (Sandbox Code Playgroud)

或者,当它调用x.doSomething()时,依赖它抛出NullException是否安全?

其次,假设someMethod是一个构造函数,在调用另一个方法之前不会使用x.我应该立即抛出异常还是等到需要x然后抛出异常?

tva*_*son 60

我喜欢ArgumentNullExceptionNullReferenceException,不是检查参数将提供.通常,我的首选是在尝试在潜在的null对象上调用方法之前始终检查null.

如果该方法是构造函数,那么它将取决于几个不同的因素:是否还有该属性的公共setter以及该对象实际使用的可能性.如果有一个公共setter,那么不通过构造函数提供有效的实例是合理的,不应该导致异常.

如果没有公共setter并且可以在不引用注入对象的情况下使用包含对象,则可能需要推迟检查/异常,直到尝试使用它为止.我认为一般情况下,注入的对象对于实例的运行至关重要,因此ArgumentNull异常是完全合理的,因为没有它,实例就无法运行.

  • 是的,这不是一个偏好的问题.ArgumentNullException是正确的,NullReferenceException不是.NullReferenceException用于当<i>访问</ i>的空对象时,例如它的字段或属性. (8认同)

Chr*_*sic 31

我总是遵循快速失败的做法.如果您的方法依赖于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));
Run Code Online (Sandbox Code Playgroud)

C#6为nameof操作员提供了大大改进的防护声明.


viv*_*una 18

我强烈同意@tvanfosson 的观点。添加到他的答案中,使用 .net 6 it\xe2\x80\x99s 很容易抛出ArgumentNullException.

\n
ArgumentNullException.ThrowIfNull(object);\n
Run Code Online (Sandbox Code Playgroud)\n

这里\xe2\x80\x99是官方文档。

\n


Joe*_*orn 14

出于以下原因,我更喜欢显式异常:

  • 如果该方法具有多个SomeClass参数,则可以让您有机会说出它是哪一个(其他所有内容都在调用堆栈中可用).
  • 如果你在引用x之前做了一些可能有副作用的事情怎么办?


And*_*are 11

我同意快速失败的想法 - 然而,明智的是,为什么快速失败是切实可行的.考虑这个例子:

void someMethod(SomeClass x)
{       
    x.Property.doSomething();
}
Run Code Online (Sandbox Code Playgroud)

如果你依靠NullReferenceException告诉你出了什么问题,你怎么知道什么是空的?堆栈跟踪只会为您提供行号,而不是哪个引用为空.在这个例子中,x或者x.Property两者都可以为空并且没有事先通过激进检查快速失败,你将不知道它是什么.


Oli*_*ich 9

我更喜欢使用显式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);
Run Code Online (Sandbox Code Playgroud)

你可以看到,字符串应该是参数的名称,即null,因此给开发人员一个关于出错的提示.


And*_*rby 8

这些天没有理由不进行检查。C# 已经向前发展,您可以使用丢弃和空合并运算符非常巧妙地做到这一点:

_ = declaringType ?? throw new ArgumentNullException(nameof(declaringType));
_ = methodname ?? throw new ArgumentNullException(nameof(methodName));
Run Code Online (Sandbox Code Playgroud)


g .*_*g . 5

最好早点而不是稍后抛出ArgumentNullException.如果你抛出它,你可以提供有关问题的更多有用信息,而不是NullReferenceException.


Szy*_*zga 5

如果您希望输入不为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();
}
Run Code Online (Sandbox Code Playgroud)

NonNull方法将执行nullity检查并抛出NullArgumentException,并在调用中指定错误消息.

  • 异常中的堆栈跟踪怎么样?它将包含Guard方法NotNull,它只是噪音,可能会引起混淆.有没有办法避免这种情况? (5认同)