我有一个字符串属性具有最大长度要求,因为数据链接到数据库.如果调用者尝试设置超过此长度的字符串,我应该抛出什么异常?
例如,这个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)
- 所以ArgumentException
可以制作一个案例,但它不是作为消费者眼睛的一个功能被调用 - 它位于赋值运算符的右侧.
这个问题也可能扩展到包括在属性设置器中完成的各种数据验证,但我对上述情况特别感兴趣.
看看带有Reflector的mscorlib.dll,在类似的情况下,例如System.String.StringBuilder.Capacity,Microsoft使用ArgumentOutOfRangeException()类似于:
public int PropertyA { get { return //etc... } set { if (condition == true) { throw new ArgumentOutOfRangeException("value", "/* etc... */"); } // ... etc } }
对我来说,ArgumentException(或子)更有意义,因为您提供的参数(值)无效,这就是为其创建的ArgumentException.
我根本不会抛出异常.相反,我会允许任意长度的字符串,然后在保存之前调用的类上有一个单独的"Validate"方法.有很多场景特别是如果你使用数据绑定,从属性设置器中抛出异常会让你陷入混乱.
从属性设置器抛出异常的麻烦在于程序员忘记捕获它们.这取决于您对预期数据的清洁程度.在这种情况下,我希望长字符串长度是常见的而不是例外,因此使用异常将是"具有异常的流量控制".
引用微软开发类库的设计指南:
如果可能,不要将异常用于正常的控制流程.除了系统故障和具有潜在竞争条件的操作之外,框架设计者应该设计API,以便用户可以编写不会抛出异常的代码.例如,您可以在调用成员之前提供检查前提条件的方法,以便用户可以编写不会引发异常的代码.
还记得通过添加额外的间接级别来解决计算机科学中有多少问题?
一种方法是创建一个新类型,FixedLengthString,比方说.这种类型的实例将验证它们初始化的字符串长度 - 使用转换运算符从普通字符串进行类型转换.如果属性setter采用这样的类型作为其参数,那么任何违规都将成为类型转换异常而不是参数/属性异常.
在实践中,我很少这样做.它闻起来有点过分OO - 但在某些情况下它可能是一种有用的技术,所以我在这里提到完整性.
public IPAddress Address { get { return address; } set { if(value == null) { throw new ArgumentNullException("value"); } address = value; } }
通过MSDN