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

时间:2021-09-10 20:31:42

In my application I need to throw an exception if a property of a specific class is null or empty (in case it's a string). I'm not sure what is the best exception to use in this case. I would hate to create a new exception and I'm not sure if ArgumentNullException is appropriate in this case.

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

Should I create a new exception or there's an exception I can use?

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

I don't mind to throw an ApplicationException.

我不介意抛出一个ApplicationException。

9 个解决方案

#1


66  

The MSDN guidelines for standard exceptions states:

MSDN标准异常指南规定:

Do use value for the name of the implicit value parameter of property setters.

请使用value作为属性setter的隐式值参数的名称。

The following code example shows a property that throws an exception if the caller passes a null argument.

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

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

Additionally, the MSDN guidelines for property design say:

此外,MSDN的财产设计指南说:

Avoid throwing exceptions from property getters.

避免从属性getter中抛出异常。

Property getters should be simple operations without any preconditions. If a getter might throw an exception, consider redesigning the property to be a method. This recommendation does not apply to indexers. Indexers can throw exceptions because of invalid arguments.

属性getter应该是简单的操作,没有任何先决条件。如果getter可能抛出异常,请考虑将该属性重新设计为方法。此建议不适用于索引器。由于参数无效,索引器可能会抛出异常。

It is valid and acceptable to throw exceptions from a property setter.

从属性设置器中抛出异常是有效且可接受的。

So throw ArgumentNullException in the setter on null, and ArgumentException on the empty string, and do nothing in the getter. Since the setter throws and only you have access to the backing field, it's easy to make sure it won't contain an invalid value. Having the getter throw is then pointless. This might however be a good spot to use Debug.Assert.

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

If you really can't provide an appropriate default, then I suppose you have three options:

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

  1. Just return whatever is in the property and document this behaviour as part of the usage contract. Let the caller deal with it. You might also demand a valid value in the constructor. This might be completely inappropriate for your application though.

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

  2. Replace the property by methods: A setter method that throws when passed an invalid value, and a getter method that throws InvalidOperationException when the property was never assigned a valid value.

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

  3. Throw InvalidOperationException from the getter, as you could consider 'property has never been assigned' an invalid state. While you shouldn't normally throw from getters, I suppose this might be a good reason to make an exception.

    从getter中抛出InvalidOperationException,因为您可以认为“属性从未被分配”为无效状态。虽然你通常不应该从getter中抛出,但我认为这可能是做出异常的一个很好的理由。

If you choose options 2 or 3, you should also include a TryGet- method that returns a bool which indicates if the property has been set to a valid value, and if so returns that value in an out parameter. Otherwise you force callers to be prepared to handle an InvalidOperationException, unless they have previously set the property themselves and thus know it won't throw. Compare int.Parse versus int.TryParse.

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

I'd suggest using option 2 with the TryGet method. It doesn't violate any guidelines and imposes minimal requirements on the calling code.

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


About the other suggestions
ApplicationException is way too general. ArgumentException is a bit too general for null, but fine otherwise. MSDN docs again:

关于其他建议ApplicationException太笼统了。 ArgumentException对于null来说有点过于笼统,但是否则会很好。再次MSDN文档:

Do throw the most specific (the most derived) exception that is appropriate. For example, if a method receives a null (Nothing in Visual Basic) argument, it should throw System.ArgumentNullException instead of its base type System.ArgumentException.

抛出最合适的(最派生的)异常。例如,如果方法接收null(在Visual Basic中为Nothing)参数,则应抛出System.ArgumentNullException而不是其基类型System.ArgumentException。

In fact you shouldn't use ApplicationException at all (docs):

实际上你根本不应该使用ApplicationException(docs):

Do derive custom exceptions from the T:System.Exception class rather than the T:System.ApplicationException class.

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

It was originally thought that custom exceptions should derive from the ApplicationException class; however, this has not been found to add significant value. For more information, see Best Practices for Handling Exceptions.

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

InvalidOperationException is intended not for when the arguments to a method or property are invalid, but for when the operation as a whole is invalid (docs). It should not be thrown from the setter:

InvalidOperationException不适用于方法或属性的参数无效的情况,也适用于整个操作无效的情况(docs)。它不应该从setter抛出:

Do throw a System.InvalidOperationException exception if in an inappropriate state. System.InvalidOperationException should be thrown if a property set or a method call is not appropriate given the object's current state. For example, writing to a System.IO.FileStream that has been opened for reading should throw a System.InvalidOperationException exception.

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

Incidentally, InvalidOperationException is for when the operation is invalid for the object's current state. If the operation is always invalid for the entire class, you should use NotSupportedException.

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

#2


4  

I would throw an InvalidOperationException. MSDN says it "is thrown when a method call is invalid for the object's current state."

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

#3


2  

Well, it's not an argument, if you're referencing a property of a class. So, you shouldn't use ArgumentException or ArgumentNullException.

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

NullReferenceException would happen if you just leave things alone, so I assume that's not what you're looking for.

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

So, using ApplicationExeption or InvalidOperationException would probably be your best bet, making sure to give a meaningful string to describe the error.

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

#4


2  

It is quite appropriate to throw ArgumentNullException if anyone tries to assign null.

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

A property should never throw on a read operation.

属性永远不应该抛出读操作。

#5


1  

Does the constructor set it to a non-null value? If so I would just throw ArgumentNullException from the setter.

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

#6


1  

If the problem is that a member of an argument, and not the argument itself, is null then I think the best choice is the more generic ArgumentException. ArgumentNullException does not work here because the argument is in fact not null. Instead you need the more generic "something is wrong with your argument" exception type.

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

A detailed message for the constructor would be very appropriate here

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

#7


1  

If it can't be null or empty, have your setter not allow null or empty values, or throw an ArgumentException if that is the case.

如果它不能为null或为空,请让您的setter不允许null或空值,否则抛出ArgumentException(如果是这种情况)。

Also, require that the property be set in the constructor.

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

This way you force a valid value, rather than coming back later and saying that that you can't determine account balance as the account isn't set.

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

But, I would agree with bduke's response.

但是,我同意bduke的回应。

#8


1  

There is a precedent for stretching the interpretation of ArgumentNullException to meaning "string argument is null or empty": System.Windows.Clipboard.SetText will throw an ArgumentNullException in this case.

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

So I wouldn't see anything wrong with using this rather than the more general ArgumentException in your property setter, provided you document it.

因此,如果您记录它,我认为在您的属性设置器中使用它而不是更一般的ArgumentException也不会有任何问题。

#9


0  

Just throw whatever as long as the error message is helpful to a developer. This class of exception should never happen outside of development, anyway.

只要错误消息对开发人员有帮助就扔掉任何东西。无论如何,这类异常绝不应该发生在开发之外。

#1


66  

The MSDN guidelines for standard exceptions states:

MSDN标准异常指南规定:

Do use value for the name of the implicit value parameter of property setters.

请使用value作为属性setter的隐式值参数的名称。

The following code example shows a property that throws an exception if the caller passes a null argument.

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

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

Additionally, the MSDN guidelines for property design say:

此外,MSDN的财产设计指南说:

Avoid throwing exceptions from property getters.

避免从属性getter中抛出异常。

Property getters should be simple operations without any preconditions. If a getter might throw an exception, consider redesigning the property to be a method. This recommendation does not apply to indexers. Indexers can throw exceptions because of invalid arguments.

属性getter应该是简单的操作,没有任何先决条件。如果getter可能抛出异常,请考虑将该属性重新设计为方法。此建议不适用于索引器。由于参数无效,索引器可能会抛出异常。

It is valid and acceptable to throw exceptions from a property setter.

从属性设置器中抛出异常是有效且可接受的。

So throw ArgumentNullException in the setter on null, and ArgumentException on the empty string, and do nothing in the getter. Since the setter throws and only you have access to the backing field, it's easy to make sure it won't contain an invalid value. Having the getter throw is then pointless. This might however be a good spot to use Debug.Assert.

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

If you really can't provide an appropriate default, then I suppose you have three options:

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

  1. Just return whatever is in the property and document this behaviour as part of the usage contract. Let the caller deal with it. You might also demand a valid value in the constructor. This might be completely inappropriate for your application though.

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

  2. Replace the property by methods: A setter method that throws when passed an invalid value, and a getter method that throws InvalidOperationException when the property was never assigned a valid value.

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

  3. Throw InvalidOperationException from the getter, as you could consider 'property has never been assigned' an invalid state. While you shouldn't normally throw from getters, I suppose this might be a good reason to make an exception.

    从getter中抛出InvalidOperationException,因为您可以认为“属性从未被分配”为无效状态。虽然你通常不应该从getter中抛出,但我认为这可能是做出异常的一个很好的理由。

If you choose options 2 or 3, you should also include a TryGet- method that returns a bool which indicates if the property has been set to a valid value, and if so returns that value in an out parameter. Otherwise you force callers to be prepared to handle an InvalidOperationException, unless they have previously set the property themselves and thus know it won't throw. Compare int.Parse versus int.TryParse.

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

I'd suggest using option 2 with the TryGet method. It doesn't violate any guidelines and imposes minimal requirements on the calling code.

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


About the other suggestions
ApplicationException is way too general. ArgumentException is a bit too general for null, but fine otherwise. MSDN docs again:

关于其他建议ApplicationException太笼统了。 ArgumentException对于null来说有点过于笼统,但是否则会很好。再次MSDN文档:

Do throw the most specific (the most derived) exception that is appropriate. For example, if a method receives a null (Nothing in Visual Basic) argument, it should throw System.ArgumentNullException instead of its base type System.ArgumentException.

抛出最合适的(最派生的)异常。例如,如果方法接收null(在Visual Basic中为Nothing)参数,则应抛出System.ArgumentNullException而不是其基类型System.ArgumentException。

In fact you shouldn't use ApplicationException at all (docs):

实际上你根本不应该使用ApplicationException(docs):

Do derive custom exceptions from the T:System.Exception class rather than the T:System.ApplicationException class.

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

It was originally thought that custom exceptions should derive from the ApplicationException class; however, this has not been found to add significant value. For more information, see Best Practices for Handling Exceptions.

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

InvalidOperationException is intended not for when the arguments to a method or property are invalid, but for when the operation as a whole is invalid (docs). It should not be thrown from the setter:

InvalidOperationException不适用于方法或属性的参数无效的情况,也适用于整个操作无效的情况(docs)。它不应该从setter抛出:

Do throw a System.InvalidOperationException exception if in an inappropriate state. System.InvalidOperationException should be thrown if a property set or a method call is not appropriate given the object's current state. For example, writing to a System.IO.FileStream that has been opened for reading should throw a System.InvalidOperationException exception.

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

Incidentally, InvalidOperationException is for when the operation is invalid for the object's current state. If the operation is always invalid for the entire class, you should use NotSupportedException.

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

#2


4  

I would throw an InvalidOperationException. MSDN says it "is thrown when a method call is invalid for the object's current state."

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

#3


2  

Well, it's not an argument, if you're referencing a property of a class. So, you shouldn't use ArgumentException or ArgumentNullException.

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

NullReferenceException would happen if you just leave things alone, so I assume that's not what you're looking for.

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

So, using ApplicationExeption or InvalidOperationException would probably be your best bet, making sure to give a meaningful string to describe the error.

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

#4


2  

It is quite appropriate to throw ArgumentNullException if anyone tries to assign null.

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

A property should never throw on a read operation.

属性永远不应该抛出读操作。

#5


1  

Does the constructor set it to a non-null value? If so I would just throw ArgumentNullException from the setter.

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

#6


1  

If the problem is that a member of an argument, and not the argument itself, is null then I think the best choice is the more generic ArgumentException. ArgumentNullException does not work here because the argument is in fact not null. Instead you need the more generic "something is wrong with your argument" exception type.

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

A detailed message for the constructor would be very appropriate here

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

#7


1  

If it can't be null or empty, have your setter not allow null or empty values, or throw an ArgumentException if that is the case.

如果它不能为null或为空,请让您的setter不允许null或空值,否则抛出ArgumentException(如果是这种情况)。

Also, require that the property be set in the constructor.

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

This way you force a valid value, rather than coming back later and saying that that you can't determine account balance as the account isn't set.

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

But, I would agree with bduke's response.

但是,我同意bduke的回应。

#8


1  

There is a precedent for stretching the interpretation of ArgumentNullException to meaning "string argument is null or empty": System.Windows.Clipboard.SetText will throw an ArgumentNullException in this case.

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

So I wouldn't see anything wrong with using this rather than the more general ArgumentException in your property setter, provided you document it.

因此,如果您记录它,我认为在您的属性设置器中使用它而不是更一般的ArgumentException也不会有任何问题。

#9


0  

Just throw whatever as long as the error message is helpful to a developer. This class of exception should never happen outside of development, anyway.

只要错误消息对开发人员有帮助就扔掉任何东西。无论如何,这类异常绝不应该发生在开发之外。