Yushatak Yushatak - 3 months ago 15
C# Question

Try/Catch — How do I know what to catch in odd/complex cases?

I know why I shouldn't use open catch blocks like so:

int x = 0;
try
{
x = GetXFromSomeplaceThatCanFail();
}
catch //Possibly (Exception) or (Exception e)
{
//Ignore The Failure Because We Don't Care If It Fails
}
if (x != 0) //Yes I know I can use finally blocks to do something similar, but this is just an example case
{
//Do Things With x
}


I'm fully aware that this will "swallow" things like OutOfMemoryException, which is bad practice and can cause undetected failures/subtle errors, which are awful things.

That's why I'm going through my code and making sure there are no things like this. Normally you'd go to the documentation of whatever you're using in the try block and catch the expected exceptions, or else know that certain operations generate certain exceptions (like an IndexOutOfRangeException when accessing an array with an index, etc.).

However, there is no documentation to check in odd situations to see what exceptions may be thrown (or it's hard to find). A specific case from my own project (variable names made generic and code simplified) uses the dynamic type to grab a string field only if it exists or else fails gracefully by providing "N/A" as the result. Again, I remind you that I know that this is bad code:

string theString = "Some Old Value From Previous Run/etc.";
try
{
theString = (placeWhereValuesComeFrom as dynamic).TheString;
}
catch
{
theString = "N/A";
}


In this context, placeWhereValuesComeFrom inherits from BaseClass which doensn't (nor should it) provide TheString.

I realize that I could create an intermediate class that offers TheString and inherits from BaseClass, and then inherit from that. However, the dynamic solution was really fast to put in place and works well. Unless a better solution is put forth for my specific scenario I plan to add an intermediate class and make only the relevant classes inherit from it, then test like so:

theString = placeWhereValuesComeFrom is Subclass ? ((Subclass)placeWhereValuesComeFrom).TheString : "N/A";


However, under the assumption that I don't want to refactor for whatever reason to use an intermediate class, what should I do here? How can I discover what possible exceptions I should safely ignore in the catch block(s)? What about other similar situations where there's no real way to just "look up" what exceptions can be thrown?

Answer

The only exception you should be handling here is a runtime binding failure; when the dynamic object does not implement TheString. The type of the exception thrown is Microsoft.System.CSharp.RuntimeBinder.RuntimeBinderException.

So your code should be the following:

try
{
    str = myDynamicObject.TheString;
}
catch (Microsoft.System.CSharp.RuntimeBinder.RuntimeBinderException)
{
    //Binding failure
    str = "N/A"
}
catch ( ... //exceptions you know TheString can throw, if any...)
{
    //Handle
}
// any other exception you don't know how To handle...don't handle it