Rick Strahl's Web Log

Wind, waves, code and everything in between...
ASP.NET • C# • HTML5 • JavaScript • AngularJs
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Explicitly Ignoring Exceptions in C#


On this page:

This post falls in the stupid pet tricks category. In most applications I have a few places where I explicitly need to ignore errors. You know the stuff where you use a try/catch blocks without any actual filter to capture the exception:

try
{
   File.Delete(filename); 
}
catch
{
}

This code, besides being very verbose, also triggers analyzer warnings that complain about the 'inappropriate use of a try/catch' block. And let's not forget to mention anybody who reviews the code immediately throwing the book at you (you know who you are Mr. Bookthrower).

Ignored Exceptionalism

In this world of Exceptionalizm we all are very sensitive to taking exception. So, let me start this post by saying that ignoring exceptions generally is a bad idea. In just about all situations where you put a try/catch around a block of code, you should always have an appropriate catch handler that captures a specific exception like (UnAuthorizedAccessException ex) - or even a non-specific exception like (Exception ex) to pass on or otherwise handle the exception in the appropriate location.

It's best to handle exceptions as close as possible to the source because the closer you are the more context you have to do something useful with the exception.

But, as with all rules in my book: Rules are meant to be broken!

Cue Dr. Evil laugh track... Muuaaaahhaaaa!

Ignorance is Bliss

Alas, in almost every application I find myself in situations where I simply don't care about a thrown exception. So yeah, I can pretend to handle the exception properly with an exception filter, but then still really do nothing with it. This satisfies the analyzer rule engines, but certainly not your friendly neighborhood book thrower in a code review.

So when does it actually make sense to ignore exceptions? Here are a couple of examples that apply to me.

The most common scenario tends to be disk based operations where I need to read/write to files and the files don't exist. Right now in Markdown Monster I do quite a few asynchronous background operations that do things like writing a backup file, or checking whether a checksum of a file has changed to ensure that the file on disk and what's in the editor stay in sync. There are lot of things that can cause file operations to fail there due to file locking conflicts or timing errors and often I don't care if it fails, because it's one of many operations that'll be handled in the next round of events. There are high level operations like the final file save/load operations that have explicit handlers, but a lot of the lower level ones can just silently fail.

Also in Markdown Monster there are a lot of HTTP based check operations if URL content exits. Checking for blog discovery URLs, for dictionary spell checker and license URLS require a check of a URL which will throw on failure and I don't care about the exceptions just whether it worked or not.

Also file operations like File.DeleteFile() or Directory.DeleteDirectory() fail if files or directories aren't there. Well if they're not there for all intents and purposes those operations succeeded because the file/dir isn't there anymore, is it now?

In all those cases I don't care about the failure and essentially I just want to ignore it or at best be notified yay or nay of the failure.

Explicit Ignorance

So, pragmatic creature I tend to be, I created a couple of small helper functions that make ignoring errors very explicit and maybe a little less verbose. So rather than writing a messy, book thrower prone try/catch block, I can write something like this:

// safe delete
LanguageUtils.IgnoreErrors(() => File.Delete(workFile)); 

or something that actually checks for the success of the operation:

// Create a directory and if it works return the name
if (LanguageUtils.IgnoreErrors(() => { Directory.CreateDirectory(workFolder); }))  
    return workFolder;         

or using the generic version which allows me to return a result value or a default:

// with parameter results
var html = LanguageUtils.IgnoreErrors<string>(()=> HttpUtils.HttpGetString(url));
if (html == null)
   Model.Window.ShowStatusError("Download failed...");

Take that book throwers!

All kidding aside, this makes the code very explicit by stating my intent which is: I am choosing to throw caution to the wind, just let me do my thing!. To my eye this also reads cleaner and requires less bracket typing than a try/catch block which helps reduce code clutter.

The implementation of these helpers is simple enough:

public static class LanguageUtils
{
    /// <summary>
    /// Runs an operation and ignores any Exceptions that occur.
    /// Returns true or falls depending on whether catch was
    /// triggered
    /// </summary>
    /// <param name="operation">lambda that performs an operation that might throw</param>
    /// <returns></returns>
    public static bool IgnoreErrors(Action operation)
    {
        if (operation == null)
            return false;
        try
        {
            operation.Invoke();
        }
        catch
        {
            return false;
        }

        return true;
    }

    /// <summary>
    /// Runs an function that returns a value and ignores any Exceptions that occur.
    /// Returns true or falls depending on whether catch was
    /// triggered
    /// </summary>
    /// <param name="operation">parameterless lamda that returns a value of T</param>
    /// <param name="defaultValue">Default value returned if operation fails</param>
    public static T IgnoreErrors<T>(Func<T> operation, T defaultValue = default(T))
    {
        if (operation == null)
            return defaultValue;

        T result;
        try
        {
            result = operation.Invoke();
        }
        catch
        {
            result = defaultValue;
        }

        return result;
    }
}

I kind of think of these functions as SafeEval() operations, because effectively that's what they are doing: They let you write lambda functions to pass in and execute inside of an exception handler. The first version returns true and false depending on whether the handler was triggered, the second one returns a result value or the default value for the passed generic argument.

The main benefit I see from these helpers is readability - you're effectively making it very explicit what you are doing by announcing that you are ignoring errors. It also helps by making it easy to capture the failure case with a simple logical value, or with a known result and failure values.

Keep in mind there's some small overhead to using this over using a try/catch handler - this ends up translating: Each Lambda you create generates a closure structure that so there is an extra structure and an extra function call involved in all of this.

So, clearly this is a feature geared at code readability and explicitness rather than providing any real runtime benefit.

Again I want to be clear: Just like the try/catch handler without an exception filter, this should be used sparingly and only when you explicitly know that you want to ignore an exception or don't care about the exception and just need to know whether it worked.

Summary

As I said at the outset this falls under Stupid Pet Tricks and a very simple one at that. However, after creating this little helper and digging through the Markdown Monster source I found nearly 30 instances of non-specific try catch blocks that could benefit from this code and using this function certainly ended up making those bits more readable. Maybe some of you will also find this little nugget useful. Enjoy.

Resources

this post created and published with Markdown Monster
Posted in C#  .NET  

The Voices of Reason


 

Ryan
June 16, 2018

# re: Explicitly Ignoring Exceptions in C#

I like this. I'm going to steal it for the Java stuff I'm working on at work, where the situation is even worse due to checked exceptions. This looks like a good way to communicate "Yes, I know there's a checked exception here, and I don't care."


Kevin Rich
June 17, 2018

# re: Explicitly Ignoring Exceptions in C#

I like that this is clean and offers the future maintainers of code the explicit statement that "I meant to do that."


holger leichsenring
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

Sure there are situations that makes it necessary to catch an exception and do not communicate the possible cause for it to the caller of the function. There are two things that came to my head about this approach:

  • Why not writing out to log when an exception had been thrown? There are rare cases when an exception can really be ignored at all (thinking about COM ObjectModel traversal in Excel), in most cases, catching an exception means to write a log entry. Actually to avoid debugging at least.
  • I do like the library exactly because of the reason mentioned before: When I anyway expect an exception to be raised and I want to handle it in a certain way, there should be library to take away the boilerplate code. The lib makes it easy to communicate to the next maintainer of the code that this was intentially. This raises the question when this lib needs to be used and when not, especially. The latter due to the fact, that "ignoring exceptions" (which should better be read as: I expect an exception to be raised and I handle it in a certain way due to, I know exactly how) can happen, but a rare.

Finally, I have to confess, I do not like your samples. Let's take this: if (LanguageUtils.IgnoreErrors(() => { Directory.CreateDirectory(workFolder); }))
return workFolder;


Matthias Schippling
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

I think my colleagues would consider me one of those bookthrowers 😉. My problem with the empty catch block is, that it's not clear if it was really the intent of the author or just forgotten error handling or logging. So until now I usually just wrote "// ignore exception" or a similar comment in the catch block.

I think your helper method is also a good way to make it explicit.


Anderson
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

Hey, Rick

Do you believe as just did it a couple of weeks ago? Not exactly the same implementation obviously, but pretty similar. But I still had some problems with the Mr. Bookthrower...I'm going to share this link with him =)

One thing I did differently was receiving another action to be executed inside the catch that you could use for logging purposes or in your case, you could pass something like that: () => Model.Window.ShowStatusError("Download failed...");

Oh, any reason to use operation.Invoke() instead of operation()?


Peter Campbell
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

This is great, its always bothered me when I have had to ignore exceptions. File operations in particular tend to through these up.


Oliver
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

Your customer will love you. No exceptions at all, what a wonderful world. Even if you had bugs in your app (like operation is null) your app will behave as if it is correct. It must be the customer who is wrong.

Yes, I do know situations where I also eat all exceptions, but these are very rare and most the times while shutdown the app. A try catch with an explicit comment in catch block why I do not care for exceptions here is fine and a good discussion point if someone knows better.

IMHO introducing this IgnoreErrors is the wrong signal to the whole development team and will lead to „Exceptions? Hey, just use IgnoreError, compile and ship!“


Chris K
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

This is just about the best idea I've ever seen. (Maybe a bit of an exaggeration, blame it on the caffeine.)


Lucas
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

I understand the desire to not handle exceptions which do not cause a break in the application logic or process flow, but here's a question: Why not use the catch parameter to explicitly ignore specific types of exceptions instead of ignoring all exceptions with the unqualified catch? To use one of the examples stated in the article where a click event causes an exception, well, what if somebody edited that click event after you implemented your handy "IgnoreErrors" helper, and suddenly you're ignoring a new exception that you wouldn't have expected to see before that actually needs to be handled? Heck, wouldn't it even be possible to pass an exception type (or list of exception types) into your IgnoreErrors method? That way you could specify which exceptions you wanted to ignore, so if the implementation changes later, you are less likely to swallow critical errors.


Chuck
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

Nice! Thanks.


Rick Strahl
June 18, 2018

# re: Explicitly Ignoring Exceptions in C#

@Oliver - I think you're missing the point. First off handling an exception with a proper filter and then still ignoring the error (because there's nothing that you can or should do beyond acknowledging that a failure occured) is no better than using an empty block or this IgnoreErrors implementation. My point is that there are legitimate scenarios where you explicitly want to ignore an error - and I've given examples as they apply to me and my reasoning. If you tell me that you never have those use cases I'd be very surprised.

I'm not advocating ignoring errors to make shit work that isn't working. I'm advocating being explicit about where you choose to ignore an error. And if the use case is frivolous and trying to hide a problem a code review should still find and deal with that issue.


Chris J Breisch
June 20, 2018

# re: Explicitly Ignoring Exceptions in C#

In general, I don't have a problem with this if used explicitly and sparingly. In fact, I have already used it on a small project. I did change your class name to ExceptionHandler, and your method name to Try(). That makes more sense to me and seems more consistent with things like Int.TryParse().

However, I would point out that this is in violation to "Uncle Bob"'s writings on Command Query Separation from Clean Code.

Functions should either do something or answer something, but not both. Either your function should change the state of an object, or it should return some information about that object. Doing both often leads to confusion. Consider, for example, the following function:

public boolean set(String attribute, String value); 

This function sets the value of a named attribute and returns true if it is successful and false if no such attribute exists. This leads to odd statements like this:

if (set(”username”, ”unclebob”))… 

Imagine this from the point of view of the reader. What does it mean? Is it asking whether the “username” attribute was previously set to “unclebob”? Or is it asking whether the “username” attribute was successfully set to “unclebob”? It’s hard to infer the meaning from the call because it’s not clear whether the word “set” is a verb or an adjective.

The author intended set to be a verb, but in the context of the if statement it feels like an adjective. So the statement reads as “If the username attribute was previously set to unclebob” and not “set the username attribute to unclebob and if that worked then.…” We could try to resolve this by renaming the set function to setAndCheckIfExists, but that doesn’t much help the readability of the if statement. The real solution is to separate the command from the query so that the ambiguity cannot occur.

if (attributeExists(”username”)) {
     setAttribute(”username”, ”unclebob”);
     …
}

However, the main issue that I have with this is that it needs to be used sparingly. Swallowing exceptions is almost never a good idea. The advantage of this, though is that it makes it clear that the developer wanted to swallow the exception, and didn't just forget to do something in the catch block.

My other issue with it, though is that often when I want to swallow an exception, it may be just a specific type. Consider your DeleteFile example. This could fail because the file didn't exist, as you suggest. But it might have failed because I don't have permissions to delete the file, or it's open and can't be deleted, or several other reasons. Blindly ignoring the error and assuming that the file is already deleted is guaranteed to bite you later on.


Jojo Aquino
June 21, 2018

# re: Explicitly Ignoring Exceptions in C#


me: "i really think we should handle this kind of exception because reasons"
co-worker: "its ok, i explicitly ignored it using lambda and generics and whatnot"

Dmitry Pavlov
June 21, 2018

# re: Explicitly Ignoring Exceptions in C#

I used to create similar safe try-catchers for actions. It was especially useful when you have a chain of operations to perform and you'd like to execute them one by one. The next operation should be performed only if the previous one succeeded. So it make sense to combine these "LanguageUtils" helpers with fluent interface approach and also turn them into extension methods of some "IOperation".


Rob
June 22, 2018

# re: Explicitly Ignoring Exceptions in C#

Consider the StackOverflowException and the OutOfMemoryException. If you blindly ignored those, you'd never know they occurred. You also wouldn't know why your application is in an inconsistent state or why it crashes when it executes arbitrary code shortly after such Exceptions are thrown.

Speaking from experience, if you blindly ignore Exceptions, you'll have a difficult time determining the cause of random errors (even if you had a Memory Dump when the app crashed). At the very least, I'd log the Exception and then either re-throw the original Exception or throw a more specific Exception with the original Exception as the Inner Exception.

I'm not so naive to believe I know everything. I can only speak from experience. If you have a real-world example where blindly catching such Exceptions is absolutely necessary, I'd certainly like to learn.

-rob

 

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2018