接口实现应该如何处理调用者可能期望的类型的意外内部异常
本文关键字:期望 类型 异常 内部 意外 调用者 实现 何处理 处理 接口 | 更新日期: 2023-09-27 18:01:54
如果一个类实现了一个接口,它应该如何处理以下情况:
- 在执行一个方法或属性时,发生了一个内部错误,该错误的类型是调用者可能合理地期望处理的,但调用者可能不应该处理。例如,字典。Add在内部做一些事情,在暗示字典损坏的情况下产生ArgumentException,但不会暗示系统的其余部分有任何不好的情况下?或者它们暗示了字典之外的东西已经被损坏了?调用者可能希望捕获并处理字典中存在重复键的事实,因为在某些情况下,异常可能是令人烦恼的(例如,相同的代码可能用于未被其他线程访问的字典和ConcurrentDictionary,如果尝试添加重复记录导致干净失败,语义将是可行的)。让ArgumentException渗透将导致调用者认为字典处于与从未发生添加相同的状态,这可能是危险的,但抛出其他异常类型似乎会令人困惑。
- 在执行方法或属性时,调用者可能应该或不应该处理的异常发生了,接口的定义没有提供任何提示,即使是远程相关的异常也可能发生。例如,假设在IEnumerator的求值中出现了错误,要么意味着(1)枚举器损坏了(可能是由于另一个线程的意外操作),但重试枚举可能会成功;(2)可枚举对象本身可能损坏或不可用,但系统中的其他一切可能都是好的(例如,一个惰性评估的文件解析例程命中无效记录);(3)超出可枚举对象的东西已经损坏。IEnumerable只有一个可以抛出的定义异常,但调用者可能希望根据异常的"严重程度"改变其操作。
顺便说一句,有一种模式我还没有见过实现,但似乎很有用,那就是在方法失败的情况下,方法接受一个委托参数来执行,这会导致"try"方法返回false。这样一个由调用方提供的委托,不仅可以抛出接收者知道要查找的异常,而且还可以设置一个只有调用方可用的标志。因此,调用者可以知道被捕获的异常确实是预期的异常。
接口的工作是定义类必须具有的成员(及其签名),而不是如何实现它们。因此,我会说,让异常向上冒泡堆栈。如果你真的想定义契约和控制一些实现(比如错误处理),那么你应该创建一个基类(在这种情况下,我倾向于MustInherit/Abstract类),基类从它的方法中调用MustOverride方法(在你的情况下,在Try Catch中,这样你就可以做你的特殊错误处理)。