I was wondering how to decide between :
1) If to throw custom exceptions OR
2) return a kind of LOG object that has flags like 'CityNotFound,' 'ReferenceConstraintBroken' etc.
I have been reading the exceptions are expensive. If I just need to know specific details of a process result, to me it sounds more beneficial to have a custom 'process LOG object' that contains only the necessery information of a process.
So, if I come back to my question:
When is better to throw an exception and when is better to return some error log 'object' ?
Throw an exception to provide more information (type of exception, message, etc.) for proper handling and to signify that:
I would actually discourage returning "log objects" (i.e. returning an exception object rather than throwing one) as this
if
statements to check the result AND handle a potential error
out
param) or else you cannot "bubble up" the error/exception for scoped handling, resulting in further limitationsIf you want to return "log objects", you should really use boolean returns with methods that makes sense (i.e. FindCity
) or methods with an out
boolean parameter (i.e. TryFindCity
). This way, you don't need to specify flags, but just use the methods whose boolean return allows you to determine the would-be flag value.
EDIT
Per OP's comment, if there is a giant method with numerous possible validation errors, then the giant method should be refactored to call smaller methods that each throw the appropriate exception. The giant method can then simply re-throw each exception or just allow each exception to bubble up if it shouldn't be the one handling it.
If there are validation dependencies that prevent "proper separation", then simply throw a single ValidationException
with the proper argument(s). An example of what this class could be is below:
public class ValidationException : Exception {
private readonly object _Field;
public object Field { get { return _Field; } }
public ValidationException(string message) : base(message) { }
public ValidationException(string message, object field)
: this(message) {
_Field = field;
}
}
Then you can just throw one exception explaining the validation error.
If you're concerned about the performance of exceptions, you could factor towards the "tester-doer" pattern, which can be used to avoid them in most cases (it also makes the code more readable than a try/catch in my opinion).
// Traditional try catch
try
{
var record = myDb.myTable.Select(primaryKey);
// do something with record...
}
catch (RecordNotFoundException)
{
// The record not found in the database... what to do?
}
// Tester-doer pattern
if (myDb.myTable.RecordExists(primaryKey))
{
var record = myDb.myTable.Select(primaryKey);
// do something with record...
}
else
{
// The record not found in the database... what to do?
}
Same result, no exceptions. The cost is you have to write the "RecordExists" function yourself, usually it would be as simple as doing something like return COUNT FROM myTable WHERE PrimaryKey=foo == 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With