Before everyone espouses code correctness, I realize that the generally correct way to do things is to not use try/catch for control flow. However, this is a bit of an edge case, and I'd like some input on what others would do in this situation.
This is example code, not actual code, but it should get the point across. If anyone wants me to define aDictionary or some mock classes for the types here just let me know and I will.
public bool IsSomethingTrue1(string aString)
{
if (aDictionary.ContainsKey(aString)) //If the key exists..
{
var aStringField = aDictionary[aString].Field; //Get the field from the value.
if (aStringField != null) //If the field isn't null..
{
return aStringField.SubField != "someValue"; //Return whether a subfield isn't equal to a specific value.
}
}
return false; //If the key isn't found or the field is null, return false.
}
public bool IsSomethingTrue2(string aString)
{
try
{
return aDictionary[aString].Field.SubField != "someValue"; //Return whether the subfield isn't equal to a specific value.
}
catch (KeyNotFoundException) //The key wasn't in the dictionary..
{
return false;
}
catch (NullReferenceException) //The field (or the dictionary, if it is dynamically assigned rather than hardcoded) was null..
{
return false;
}
}
So, in the above example the first method checks to see if the dictionary contains the key, then if it does, it checks to see if a field is null, and returns true if a subvalue isn't equal to a specific value, otherwise it returns false. This avoids try/catch, but every single time the code is accessed it performs a check on the dictionary to see if the key is present (assuming no under-the-hood caching/etc. - let me know if there is any please), then a check to see if a field is null, and then the actual check we care about.
In the second method, we use try/catch and avoid multi-tier control logic. We immediately go "straight to the point" and try to access the value in question, and if it fails in either of the two known ways it will return false. If the code executes successfully, it may return true or false (the same as the above).
Both of these methods will get the job done, but my understanding is that the first method will do so more slowly on average if nothing goes wrong in most cases. The first method will have to check everything every time, where the second only has to handle cases where something goes wrong. There will be an extra space for an Exception on the stack, and some instructions for jumping to the different catch blocks/etc.. This should all not affect performance in the regular case where nothing is wrong other than that one stack variable, however, if I understand correctly what I've read here: Do try/catch blocks hurt performance when exceptions are not thrown?
Of course with this exact example, the difference will be negligible - however, imagine a complex scenario with a lot of checks in a complex if/then/else tree compared to a try/catch with a list of failure conditions. I realize that yes, this sort of code could always be broken down into smaller bits or otherwise refactored, but for the sake of argument let's say it can't be changed other than the control flow (there are cases where changing actual logic would require a re-validation of scientific algorithms, for example, which is costly/slow and needs to be minimized).
Textbook I realize that the answer is to use the first method, but in some cases the second method could be significantly faster.
Again, I know this is somewhat pedantic, but I really like to make sure I write the most efficient code possible in places where it counts, while keeping everything readable and maintainable (and well-commented). Thanks in advance for providing me with opinions on the matter!