Error flags or return values are generally better in cases where the immediate caller is going to deal with the invalid condition. Exceptions are generally better in cases where there are going to be many function calls which could fail in a particular way, and fault handling for all those function calls should be identical.
Oftentimes the author of a method can't t know which scenario will apply to its callers (indeed, it's common for some callers to better fit one pattern and some the other). Microsoft's preferred way of handling this is to use the pattern:
Thing GetThing(int param1, string param2);
bool TryGetThing(int param1, string param2, out Thing result);
That's certainly a better concept than confining callers to fit one pattern or the other, though I don't like the particular implementation. Microsoft explicitly recommends using separate methods, rather than using one method with a parameter that indicates whether a failure should throw an exception, but that philosophy comes at a cost: it means that if one of the steps of GetThing
or TryGetThing
can be done with a "do" or "try" method, the code for GetThing
and TryGetThing
will have to be largely duplicated, with one calling "do" methods and the other calling "try" methods.
An alternative approach would be to have a delegate or interface-type object which indicates what a "try" method should do if an exception occurs. For example, one could have a function:
Thing TryGetThing(int param1, string param2, bool ThrowOnError, out ErrorInfo errInf);
possibly with an overload which, if the last two parameters are omitted, will calls the above with true
for ThrowOnError
, and a dummy variable for errInf
. If the methods used by TryGetThing
follow a similar pattern, it may be able to call them without having to duplicate code for the try/do cases.