当属性不能为null时要使用什么异常类型?

时间:2009-09-28 17:32:42

标签: c# .net exception

在我的应用程序中,如果特定类的属性为null或为空(如果它是字符串),则需要抛出异常。我不确定在这种情况下使用的最佳例外是什么。我不想创建一个新的异常,我不确定在这种情况下ArgumentNullException是否合适。

我应该创建一个新的例外还是我可以使用的例外?

我不介意抛出一个ApplicationException。

9 个答案:

答案 0 :(得分:68)

MSDN guidelines for standard exceptions州:

  

使用value作为property的隐式value参数的名称   setter方法。

     

以下代码示例显示了一个   如果抛出异常的属性   调用者传递一个null参数。

public IPAddress Address
{
    get
    {
        return address;
    }
    set
    {
        if(value == null)
        {
            throw new ArgumentNullException("value");
        }
        address = value;
    }
}

此外,MSDN guidelines for property design说:

  

避免抛出异常   财产获取者。

     

属性getter应该很简单   没有任何先决条件的操作。   如果getter可能抛出异常,   考虑重新设计财产   是一种方法。这个建议有   不适用于索引器。索引器可以   由于无效而抛出异常   参数。

     

投掷是有效和可接受的   来自属性设置器的异常。

所以在ArgumentNullException上的setter中抛出null,在空字符串上抛出ArgumentException,并在getter中不执行任何操作。由于setter抛出并且只有您可以访问支持字段,因此很容易确保它不包含无效值。获得吸气剂是没有意义的。但这可能是使用Debug.Assert的好地方。

如果你真的无法提供适当的默认值,那么我想你有三个选择:

  1. 只需返回属性中的内容,并将此行为记录为使用合同的一部分。让呼叫者处理它。您可能还需要构造函数中的有效值。这可能完全不适合您的应用程序。

  2. 通过方法替换属性:在传递无效值时抛出的setter方法,以及在从未为属性指定有效值时抛出InvalidOperationException的getter方法。

  3. 从getter中抛出InvalidOperationException,因为您可以认为'属性从未被分配'为无效状态。虽然你通常不应该从吸气剂中扔掉,但我认为这可能是做出例外的一个很好的理由。

  4. 如果选择选项2或3,则还应包括一个TryGet-方法,该方法返回bool,指示属性是否已设置为有效值,如果是,则返回{{1}中的值。 1}}参数。否则,强制调用者准备处理out,除非他们先前已经设置了属性,因此知道它不会抛出。比较InvalidOperationExceptionint.Parse

    我建议在TryGet方法中使用选项2。它不违反任何指导原则,并对调用代码施加最低要求。


    关于其他建议
    int.TryParse过于笼统。对于ApplicationExceptionArgumentException有点过于笼统,但不然如此。 MSDN docs again

      

    抛出最具体(最派生)的异常   适当。例如,如果一个方法   收到一个null(在Visual中没有   基本的)论证,它应该抛出   而是System.ArgumentNullException   它的基本类型   System.ArgumentException

    事实上,你根本不应该使用nulldocs):

      

    从T:System.Exception类派生自定义异常,而不是T:System.ApplicationException类。

         

    最初认为自定义异常应该来自ApplicationException类;然而,这并未发现增加显着价值。有关更多信息,请参阅处理异常的最佳实践。

    ApplicationException不适用于方法或属性的参数无效,但是当操作整体无效时(docs)。它不应该被设置者抛出:

      

    如果处于不适当的状态,则抛出System.InvalidOperationException异常。如果在给定对象的当前状态的情况下属性集或方法调用不合适,则应抛出System.InvalidOperationException。例如,写入已打开以供读取的System.IO.FileStream应抛出System.InvalidOperationException异常。

    顺便提一下,InvalidOperationException适用于对象当前状态的操作无效如果整个类的操作始终无效,则应使用NotSupportedException

答案 1 :(得分:4)

我会抛出InvalidOperationException。 MSDN称,当方法调用对于对象的当前状态无效时,它会被抛出。“

答案 2 :(得分:2)

嗯,如果你引用了一个类的属性,它不是一个参数。因此,您不应该使用ArgumentException或ArgumentNullException。

如果你只是把事情单独留下就会发生NullReferenceException,所以我认为这不是你想要的。

因此,使用ApplicationExeption或InvalidOperationException可能是您最好的选择,请确保提供有意义的字符串来描述错误。

答案 3 :(得分:2)

如果有人试图指定 null,则抛出ArgumentNullException非常合适。

属性不应该抛出读操作。

答案 4 :(得分:1)

构造函数是否将其设置为非null值?如果是这样,我只会从设置器中抛出ArgumentNullException

答案 5 :(得分:1)

如果问题是参数的成员而不是参数本身是null,那么我认为最好的选择是更通用的ArgumentExceptionArgumentNullException在这里不起作用,因为参数实际上不是null。相反,你需要更通用的“你的论点有问题”的异常类型。

构造函数的详细消息在这里非常合适

答案 6 :(得分:1)

如果它不能为null或为空,请让你的setter不允许null或空值,否则抛出ArgumentException。

另外,要求在构造函数中设置属性。

通过这种方式,您可以强制使用有效值,而不是稍后返回并说明由于未设置帐户而无法确定帐户余额。

但是,我同意bduke的回应。

答案 7 :(得分:1)

有一个先例可以将ArgumentNullException的解释扩展为“字符串参数为null或为空”:在这种情况下,System.Windows.Clipboard.SetText将抛出ArgumentNullException。

因此,如果你记录它,我会发现在你的属性设置器中使用它而不是更一般的ArgumentException有什么问题。

答案 8 :(得分:0)

只要错误消息对开发人员有帮助,只需抛出任何内容即可。无论如何,这类异常绝不应该发生在开发之外。