简体   繁体   中英

Is it a good practice to cache exception instance in C#

I'm trying to find an answer on that question, which is:

Is the following code is a good practice?
Should I try to reproduce it wherever it's possible or not? and if not, why?

public class ExceptionHelper
{
    private static readonly HttpException _errorReadingRequest = new HttpException(500, "Error reading request. Buffer is empty.");
    public static Exception ErrorReadingRequest { get { return _errorReadingRequest; } }
}

public class ExceptionThrower
{
    public static void ThrowCached1()
    {
        throw ExceptionHelper.ErrorReadingRequest;
    }
    // ...
}

I've tried to throw in several places the cached instances and it seems to preserve the stack trace, from MSDN ,

The stack trace begins at the statement where the exception is thrown and ends at the catch statement that catches the exception. Be aware of this fact when deciding where to place a throw statement.

I understand that as " It stores the stack trace at the throw, not at the creation ". However, I'm wondering if there could be a problem when multiple threads try to throw the same cached instance of exception.

On the same MDSN page, they are using an helper function and it seems in the framework, they are doing the same: helper function which recreates the exception and throw.

Note: I know it's not a common case because most of the time, you want a specific message to be stored in the exception so it's easier to understand what's happening.

Maybe the question is just is throw keyword thread safe or not ?

Context:

I've stumble upon this kind of code, while code reviewing some performance touchy application code. The goal is to create the maximum of instance during startup and then never (or almost never) instances during execution, in order to limit the GC performance impact (especially because of heap fragmentation occuring with GCHandle thing). I had a bad feeling about this code but needed facts to support my refactoring.

Generally it makes no sense to have one cached exception. CREATING an object is fast. Exceptions shoudl be rare - and catching them has some overhead, as has throwing them. THere is simply nothing gained from having "one exception to rule them all", except:

  • Threading issues
  • More convoluted code
  • Totally ignoring coding standards I have seen in the last 20 years.

If any of those things are your goal - go along.

Maybe the question is just is throw keyword thread safe or not ?

The throw keyword is thread safe - you can have multiple threads throwing at the same time. Using the same exception though is going to get you into trouble, but it is not because the throw KEYWORD is not thread safe but because you maliciously violate thread safety by passing in the same data object.

Throwing an exception mutates that exception object. It stores the stack for example. This is a problem if you want to use the stack trace for logging purposes. You'll get randomly corrupted stacks.

Also, creating an exception object is cheap. This does not accomplish much.

@TomTom gave a great answer, I want just to point out the example for exception caching being a standard practice: TPL's Task class Exception property.

Sometimes, if the exception is thrown inside some asynchronous operation, it is a good practice to save the information about it for the moment you need the result of operation.

But! As TPL's programmers did, you should wrap the original exception inside the new one (for example, AggregateException ) so you can see the original source and stacktrace of it.

As for the GC collection's performance hit, you can use other techniques. For example, if there are a lot of objects being created and after that being collected, try to use the structs for DTO-objects instead of classes. If they will fit into a stack size, they will be collected automatically after the method ends it's execution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM