抛出一个属性setter有什么例外?

我有一个string属性具有最大长度要求,因为数据链接到数据库。 如果调用者试图设置一个超过这个长度的string,我应该抛出什么exception?

例如,这个C#代码:

public string MyProperty { get { return _MyBackingField; } set { if (value.Length > 100) throw new FooException("MyProperty has a maximum length of 100."); _MyBackingField = value; } } 

我考虑过ArgumentException ,但它看起来不正确。 从技术上讲 ,它是一个函数 – MyProperty_set(string value) – 所以可以创build一个ArgumentException的情况,但它不会被调用作为消费者眼中的函数 – 它是在赋值运算符的右侧。

这个问题大概也可以扩展到包含在属性设置器中进行的各种数据validation,但是我对上述情况特别感兴趣。

通过与Reflector的mscorlib.dll看看,在类似的情况,如System.String.StringBuilder.Capacity微软使用ArgumentOutOfRangeException()类似于:

 public int PropertyA { get { return //etc... } set { if (condition == true) { throw new ArgumentOutOfRangeException("value", "/* etc... */"); } // ... etc } } 

对我而言,ArgumentException(或者一个小孩)更有意义,因为你提供的参数(value)是无效的,这就是ArgumentException被创build的原因。

我不会抛出exception。 相反,我会允许一个任意长度的string,然后在保存之前调用的类上有一个单独的“validation”方法。 特别是在使用数据绑定的情况下,从属性设置器中抛出exception会让你陷入混乱。

从属性设置者抛出exception的麻烦在于程序员忘记抓住他们。 它的种类取决于您期望得到的数据的干净程度。 在这种情况下,我期望长的string长度是常见的,不会例外,因此使用例外将是“带有例外的stream量控制”。

引用微软开发类库的devise指南 :

如果可能的话,不要在正常的控制stream程中使用exception。 除了系统故障和具有潜在竞争条件的操作之外,框架devise者应该deviseAPI,以便用户可以编写不会抛出exception的代码。 例如,您可以提供一种在调用成员之前检查先决条件的方法,以便用户可以编写不会抛出exception的代码。

记住计算机科学中有多less问题可以通过增加额外的间接性来解决?

一种方法是创build一个新的types,FixedLengthString,说。 这将是这种types的实例,validation它们被初始化的string的长度 – 用转换运算符从普通string进行types转换。 如果你的属性setter采用了这样一个types作为它的参数,那么任何违规将变成一个types转换exception,而不是一个参数/属性exception。

在实践中,我很less这样做。 它听起来有点太OO – 但在某些情况下,它可能是一个有用的技术,所以我在这里提到它的完整性。

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

通过MSDN

您可以使用InvalidOperationException。 这是一个妥协。 我不会打扰使用一个ArgumentException。

尝试尽可能使用现有的例外。 在这种情况下使用InvalidOperationException,因为传入的值将使对象处于不一致的状态。 当需要使用自定义exception进行特定处理时,可以创build自定义exception。 在这种情况下,你只能用一些文本引发exception,所以使用InvalidOperationException。

抛出InvalidOperationException时显示传递给这个setter的值。