有时我最终不得不为类库编写方法或属性,对于该类库,没有真正的答案不是偶然,而是失败。无法确定,无法使用,无法找到,当前无法执行或没有其他可用数据。
我认为对于这种相对非异常的情况,有三种可能的解决方案可以指示C#4失败:
- 返回一个没有其他含义的魔术值(例如
null
和-1
); - 抛出异常(例如
KeyNotFoundException
); - return
false
并在out
参数中提供实际的返回值(例如Dictionary<,>.TryGetValue
)。
所以问题是:我应该在哪种非例外情况下抛出异常?而且,如果我不应该抛出:什么时候返回在实现Try*
带有out
参数的方法时产生的魔术值?(对我来说,该out
参数似乎很脏,要正确使用该参数还需要更多工作。)
我正在寻找实际的答案,例如涉及设计准则的答案(我对Try*
方法一无所知),可用性(因为我向类库提出的要求),与BCL的一致性以及可读性。
在.NET Framework基类库中,使用了所有三种方法:
- 返回一个没有其他含义的魔术值:
Collection<T>.IndexOf
返回-1,StreamReader.Read
返回-1,Math.Sqrt
返回NaN,Hashtable.Item
返回null;
- 抛出异常:
Dictionary<,>.Item
抛出KeyNotFoundException,Double.Parse
抛出FormatException; 要么
- return
false
并在out
参数中提供实际的返回值:
请注意,正如Hashtable
C#中没有泛型时创建的那样,它使用object
,因此可以null
作为魔术值返回。但是对于泛型,在中使用了例外Dictionary<,>
,而最初没有TryGetValue
。见解显然在改变。
显然,Item
- TryGetValue
和Parse
- TryParse
偶是有原因的,所以我认为抛出异常的非特殊的故障是在C#4 没有这样做。但是,Try*
即使存在,方法也不总是存在Dictionary<,>.Item
。