views:

283

answers:

8

Hi, so in my program I have parts where I use try catch blocks like this

try
{
  DirectoryInfo dirInfo = new DirectoryInfo(someString); 
 //I don't know if that directory exists
 //I don't know if that string is valid path string... it could be anything

 //Some operations here
}
catch(Exception iDontCareWhyItFailed)
{
  //Didn't work? great... we will say: somethings wrong, try again/next one
}

Of course I probably could do checks to see if the string is valid path (regex), then I would check if directory exists, then I could catch various exceptions to see why my routine failed and give more info... But in my program it's not really necessary. Now I just really need to know if this is acceptable, and what would a pro say/think about that. Thanks a lot for attention.

+5  A: 

You shouldn't use exceptions for flow control, because it hurts performance and exceptions are not designed for that purpose. Instead, you should test the Exists property to check that the directory exists

Thomas Levesque
The "exceptions hurt performance" idea is a red herring. If you're writing performance-sensitive code (and you'll know if you are) then you might avoid them. But 99% of the time (like the above code--exactly how many directories are you checking per second?) you're better off writing the simplest, clearest code you can. And frequently that means using exceptions.
Chris B.
The file/folder can be deleted between the time Exists returns `true` and you actually try to access the file/folder. That's not theoretical, it actually happens.
Lucas
@Chris B, I just do not think it is a good habit to use exceptions when there are perfectly usable alternatives that do *not* involve exceptions, particularly if the chances of the exception occuring are relatively high. Let exceptions truly be exceptions, not just for things you're too lazy to handle a better way.
Anthony Pegram
@Chris B - Using exceptions for flow control is not writing the simplest, clearest code IMO in addition to not performing well. You should try to anticipate and avoid exceptions being thrown.
Thomas
@Lucus - Indeed that is possible and I would think you *would* care about that type of exception rather than swallowing it.
Thomas
A: 

You should do the validation whenever possible. Exceptions are expensive and should be avoided where possible.

Doing checks for the path and other validation doesn't necessarily obviate the need for exception handling and try blocks. Exceptions happen all the time (directory doesn't exist, network isn't connected) it's unexpected, unforeseeable exceptions that try/catch blocks are designed to handle.

Dave Swersky
+12  A: 
  • write "mainline" code to handle expected cases.
  • write exception handling code to... wait for it... handle exceptional cases. That's why it's called "exception handling code". :-)

If a mainline, expected, everyday case is that the path doesn't exist, then write mainline code that checks whether the path exists. If an unexpected, bizarre, exceptional circumstance is that the file exists but has been locked by another user, write an exception handler that handles that exception.

Eric Lippert
What if it's an expected mainline case that the file has been locked? How do you write mainline code that checks for that?
Gabe
@gabe: I don't know. I'm not an expert on the file system objects. You should direct your question at someone who is.
Eric Lippert
What if you can't find an expert? Do you try to write the code yourself (ineptly) or do you just let the function call handle it properly and throw an exception?
Gabe
@gabe: your question is of the form "have you stopped beating your wife yet?" If I answer no, then I am still beating my wife; if I answer yes then I am admitting that I once beat my wife. The correct answer to the question is neither yes nor no, but rather a rejection of the question. You're asking me "when given the choice of two ways to write misleading, incorrect and unmaintainable code, which do you choose?" I choose neither; I try my best to do the work necessary to write clear, correct, maintainable code.
Eric Lippert
Sorry, I guess I just don't understand how your advice applies to the question at hand. If he was asking about parsing strings, your advice would mean "use `Parse` where you expect the parsing to work and `TryParse` where you don't know". Since there's no `IsPathValid` or `TryCreateDirectory` to call, and there's no good way to write them, how does your advice apply?
Gabe
I completely agree with the general approach sir, and I wish I always could do it that way. For this program that I was writing I had to deal with file-system a lot and there were many tasks that .Net didn't provide enough power to do 'mainline' code to handle expected cases. My choice ended up being writing maybe misleading or incorrect code that gets the work done rather than using interop and writing significant amount of code to deal with simple problems. Thanks for the comment though I voted up.
m0s
+1  A: 

It really depends on how you're going to handle any of those error conditions.

If in any case you're going to exit and just print the Exception, and your users are familiar with reading and understanding that kind of output, then it's totally fine, and you'd be wasting time and code to handle it more specifically.

On the other hand, if you end up having a bunch of if tests within your exception handling code to do different things based on what exception occurred, then that's pretty clear evidence that you should handle different exceptions differently.

And if your users are not "techies" and will want more helpful error messages than exception dumps, then you should do more custom error handling yourself. Even if they are techies, they would likely appreciate clearer error messages.

There's no right answer. It really depends on your target user experience.

dkamins
+1  A: 

I would not recommend a catch-all type exception handler. Instead, you should lookup DirectoryInfo and the types of exceptions it can throw. Then you should try to avoid as many as possible before you call the constructor and only catch those exceptions that you anticipate. So my code would look like:

try
{
    if ( string.IsNullOrEmpty( someString ) )
        //do something or throw an exception
    if ( someString.Length > 248 )
        //do something or throw an exception

    DirectoryInfo dirInfo = new DirectoryInfo(someString); 

    If ( !dirInfo.Exists )
        //do something or throw an exception

    //path exists and is valid
    //Some operations here
}
catch(SecurityException)
{
  //Didn't work? great... we will say: somethings wrong, try again/next one
}
catch(ArgumentException)
{
  //Didn't work? great... we will say: somethings wrong, try again/next one
}
Thomas
+1  A: 

If you truly don't care why it failed, and your program can't reasonably do anything to recover, then it's OK to do something like this; I'd rather maintain something like this than code that uses 3 try/catch blocks to do the same thing but without adding any additional value. I do like the name of the exception that communicates it isn't of importance, that's better than catching a variable named ex.

Some suggestions, however:

  1. If you're going to "catch and ignore", be more explicit about which Exception types are OK to ignore. If you know you can ignore FileNotFoundException, or any class of IOException, then just catch that.

  2. If you're going to catch a generic Exception, consider logging the exception somewhere. Your current approach could be a maintenance nightmare if a logical defect exists in your try block. For instance, say you code an off-by-one error with regards to an array index... your current code will swallow that and provide no indication that something more important than "directory does not exist" occurred.

Seth Petry-Johnson
A: 

I'm guilty of this kind of lazy coding, as well, usually when delivering quick turnaround on 'hot' features. The problem is that cleaning up the lazy code becomes a low priority, given the new stack of inevitably 'hot' feature requests, which means this kind of lazy code accumulates. These lazy Exception catch blocks then lead to swallowing genuinely unexpected problems and suddenly your application state has mutated in an unexpected way. I'm disciplining myself to not do this, because writing lazy code is like using a credit card. It lets you deliver things now that you would have had to deliver later, but it's the compounding that gets you when it's time to pay it back.

Dan Bryant
A: 

Even if you do checks yourself (it's a valid path, the path exists, you're allowed to access it, it's not locked, etc.), you still need to have the exception handling. Although it seems unlikely, there's no reason that the conditions couldn't change from the time you check them to the time you actually access the path.

As long as you need the exception handling in the first place, why do redundant checks? The OS is going have to do them all again anyway, and odds are you aren't going to get them right anyway.

Don't worry about the cost of exceptions. Compared to the cost of doing I/O, the cost of an exception is negligible.

That said, it's not good practice to catch all exceptions without doing anything. As Seth said, either catch only IOException or log the exception. If you don't, that part of the code will be really hard to debug.

Gabe