有时我最终不得不为类库编写方法或属性,对于该类库,没有真正的答案不是偶然,而是失败。无法确定,无法使用,无法找到,当前无法执行或没有其他可用数据。
我认为对于这种相对非异常的情况,有三种可能的解决方案可以指示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参数中提供实际的返回值:
请注意,正如HashtableC#中没有泛型时创建的那样,它使用object,因此可以null作为魔术值返回。但是对于泛型,在中使用了例外Dictionary<,>,而最初没有TryGetValue。见解显然在改变。
显然,Item- TryGetValue和Parse- TryParse偶是有原因的,所以我认为抛出异常的非特殊的故障是在C#4 没有这样做。但是,Try*即使存在,方法也不总是存在Dictionary<,>.Item。