抛出ArgumentNullException

时间:2008-12-15 15:41:22

标签: c# .net exception exception-handling

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

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

    x.doSomething();
}

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

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

13 个答案:

答案 0 :(得分:59)

我更喜欢ArgumentNullException而不是NullReferenceException,而不是检查参数会提供的。通常,我的首选是在尝试在潜在的null对象上调用方法之前始终检查null。

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

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

答案 1 :(得分:31)

我总是遵循快速失败的做法。如果你的方法依赖于X并且你理解X可能在null中传递,则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运算符,Guard语句得到了极大的改进。

答案 2 :(得分:14)

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

  • 如果该方法有多个SomeClass参数,它可以让你有机会说出它是哪一个(其他一切在调用堆栈中可用)。
  • 如果您在引用x之前执行可能产生副作用的内容怎么办?

答案 3 :(得分:10)

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

void someMethod(SomeClass x)
{       
    x.Property.doSomething();
}

如果你依靠NullReferenceException告诉你出了什么问题,你怎么知道什么是空的?堆栈跟踪只会为您提供行号,而不是哪个引用为空。在此示例中,xx.Property都可以为空,并且事先没有快速进行积极检查,您将无法知道它是什么。

答案 4 :(得分: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);

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

答案 5 :(得分:5)

最好尽快抛出ArgumentNullException。如果你抛出它,你可以提供有关问题的更多有用信息,而不是NullReferenceException。

答案 6 :(得分: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();
}

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

答案 7 :(得分:4)

1-如果您不想要Null值,请明确地执行此操作。否则,当其他人查看您的代码时,他们会认为接受传递Null值。

2-你能做得越快。通过这种方式,当不应该使用Null时,你不会传播“错误”的行为。

答案 8 :(得分:3)

如果你在防守方面进行编程,你应该快速失败。因此,请检查代码开头的输入和错误。你应该对你的调用者很好,并给他们提供最具描述性的错误信息。

答案 9 :(得分:3)

这几天没有借口不做检查。 C#向前发展了,您可以使用丢弃和空合并运算符非常巧妙地做到这一点:

_ = declaringType ?? throw new ArgumentNullException(nameof(declaringType));
_ = methodname ?? throw new ArgumentNullException(nameof(methodName));

答案 10 :(得分:0)

我可能会因此而被投票,但我认为完全不同。

如果遵循一个名为“never pass null”的良好做法并删除丑陋的异常检查呢?

如果参数是对象,请勿通过NULL。另外,请勿返回NULL。你甚至可以使用Null对象模式来帮助解决这个问题。

如果它是可选的,请使用默认值(如果您的语言支持它们)或创建过载。

比丑陋的例外更清洁。

答案 11 :(得分:0)

您可以使用以下语法不只是抛出ArgumentNullException,而是将该参数作为其错误文本的一部分命名。 E.g;

void SomeMethod(SomeObject someObject)
{
    Throw.IfArgNull(() => someObject);
    //... do more stuff
}

用于引发异常的类是;

public static class Throw
{
    public static void IfArgNull<T>(Expression<Func<T>> arg)
    {
        if (arg == null)
        {
            throw new ArgumentNullException(nameof(arg), "There is no expression with which to test the object's value.");
        }

        // get the variable name of the argument
        MemberExpression metaData = arg.Body as MemberExpression;
        if (metaData == null)
        {
            throw new ArgumentException("Unable to retrieve the name of the object being tested.", nameof(arg));
        }

        // can the data type be null at all
        string argName = metaData.Member.Name;
        Type type = typeof(T);
        if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
        {
            throw new ArgumentException("The expression does not specify a nullible type.", argName);
        }

        // get the value and check for null
        if (arg.Compile()() == null)
        {
            throw new ArgumentNullException(argName);
        }
    }
}

答案 12 :(得分:0)

所有代码示例都使用容易出错的 IF 子句,其中一个使用等号运算符“==”。

如果类型 override == 会发生什么?

在 C# 7 及更高版本上,使用常量模式匹配。

示例:

如果(某事为空){ throw new ArgumentNullException(nameof(something), "不能为空。");

}

相关问题