CodeTherapist / codetherapist.github.io

My Blog
https://codetherapist.com/
0 stars 1 forks source link

blog/netconf-netcore3-IAsyncDisposable/ #3

Open utterances-bot opened 4 years ago

utterances-bot commented 4 years ago

The IAsyncDisposable interface in .NET Core 3.0

https://codetherapist.github.io//blog/netconf-netcore3-IAsyncDisposable/

prince272 commented 4 years ago

I'm getting a warning 'A general exception such as System.Exception or System.SystemException is caught in a catch statement, or a general catch clause is used. General exceptions should not be caught.'

prince272 commented 4 years ago

What does that warning mean?

CodeTherapist commented 4 years ago

Thank you, for your question. I like to answer it, to help you and everyone else having the same.

Please understand, that example code in my blog posts are in general simplified and meant to be explaining a concept - they aren't usually real world code nor production ready.

But let's talk about the warning message. In general, it's bad practice to catch an exception of type System.Exception, because it is unspecific and the base class of all exceptions. You should catch most specific exceptions within your context and only when it is possible to handle them appropriately - this is what the roslyn code analyzer tries to promote with this warning.

In contrast to this, there is another best practice: the Dispose (and DisposeAsync) method should not throw any exceptions.

Now, when you are the author of a class, then you can minimize or avoid the situation of an exception within the Dispose (or DisposeAsync) method. That means you can skip the try-catch(Exception ex) as I have it in the example and the warning goes away. My example shows, how you could catch (specific) exceptions correctly within the DisposeAsync method, when you need it.

There is another benefit of having a try-catch versus no try-catch. In the code snippet below, you can see a continuation (only when an exception is thrown) of the async method, that writes out the exception stack trace - this wouldn't be possible without the try-catch that pass down the exception to the ValueTask. Be aware, this belongs to the async\await programming model, it's not specific to DisposeAsync.

public async static Task Main(string[] args)
        {
            var disposableObj = new DisposableObject();
            await disposableObj.DisposeAsync().AsTask().ContinueWith(task => {

                Console.WriteLine(task.Exception.ToString());
            }, TaskContinuationOptions.OnlyOnFaulted);
        }

Sure, you could also do a simple try-catch on the outer scope, with a similar result:

 public async static Task Main(string[] args)
        {
            var disposableObj = new DisposableObject();

            try
            {
                await disposableObj.DisposeAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

Within the DisposableObject class

public virtual ValueTask DisposeAsync()
        {
                Dispose();
                return default;
        }

I hope, my explanations are useful and I could answer all your questions.

prince272 commented 4 years ago

Thanks for your answer. I now have a better understanding of the whole idea.