I sometimes end up having to write a method or property for a class library for which it is not exceptional to have no real answer, but a failure. Something cannot be determined, is not available, not found, not currently possible or there is no more data available.

I think there are three possible solutions for such a relatively non-exceptional situation to indicate failure in C# 4:


return a magic value that has no meaning otherwise (such as null and -1);
throw an exception (e.g. KeyNotFoundException);
return false and provide the actual return value in an out parameter, (such as Dictionary<,>.TryGetValue).


So the questions are: in which non-exceptional situation should I throw an exception? And if I should not throw: when is returning a magic value perferred above implementing a Try* method with an out parameter? (To me the out parameter seems dirty, and it is more work to use it properly.)

I'm looking for factual answers, such as answers involving design guidelines (I don't know any about Try* methods), usability (as I ask this for a class library), consistency with the BCL, and readability.



In the .NET Framework Base Class Library, all three methods are used:


return a magic value that has no meaning otherwise:

Collection<T>.IndexOf returns -1,
StreamReader.Read returns -1,
Math.Sqrt returns NaN,
Hashtable.Item returns null;

throw an exception:

Dictionary<,>.Item throws KeyNotFoundException,
Double.Parse throws FormatException; or

return false and provide the actual return value in an out parameter:

Dictionary<,>.TryGetValue,
Double.TryParse.



Note that as Hashtable was created in the time when there were no generics in C#, it uses object and can therefore return null as a magic value. But with generics, exceptions are used in Dictionary<,>, and initially it didn't have TryGetValue. Apparently insights change.

Obviously, the Item-TryGetValue and Parse-TryParse duality is there for a reason, so I assume that throwing exceptions for non-exceptional failures is in C# 4 not done. However, the Try* methods didn't always exist, even when Dictionary<,>.Item existed.

I don't think that your examples are really equivalent. There are three distinct groups, each with it's own rationale for its behaviour.


Magic value is a good option when there is an "until" condition such as StreamReader.Read or when there is a simple to use value that will never be a valid answer (-1 for IndexOf).
Throw exception when the semantics of the function is that the caller is sure that it will work. In this case a non-existing key or a bad double format is truly exceptional.
Use an out parameter and return a bool if the semantics is to probe if the operation is possible or not.


The examples you provide are perfectly clear for cases 2 and 3. For the magic values, it can be argued if this is a good design decision or not in all cases. 

The NaN returned by Math.Sqrt is a special case - it follows the floating point standard.
