抛出一个属性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的值。