'What is the difference between using and await using? And how can I decide which one to use?
I've noticed that in some case, Visual Studio recommends to do this
await using var disposable = new Disposable();
// Do something
Instead of this
using var disposable = new Disposable();
// Do something
What is the difference between using
and await using
?
How should I decide which one to use?
Solution 1:[1]
Classic sync using
Classic using calls the Dispose()
method of an object implementing the IDisposable
interface.
using var disposable = new Disposable();
// Do Something...
Is equivalent to
IDisposable disposable = new Disposable();
try
{
// Do Something...
}
finally
{
disposable.Dispose();
}
New async await using
The new await using calls and await the DisposeAsync()
method of an object implementing the IAsyncDisposable
interface.
await using var disposable = new AsyncDisposable();
// Do Something...
Is equivalent to
IAsyncDisposable disposable = new AsyncDisposable();
try
{
// Do Something...
}
finally
{
await disposable.DisposeAsync();
}
The IAsyncDisposable Interface was added in .NET Core 3.0
and .NET Standard 2.1
.
In .NET, classes that own unmanaged resources usually implement the IDisposable interface to provide a mechanism for releasing unmanaged resources synchronously. However, in some cases they need to provide an asynchronous mechanism for releasing unmanaged resources in addition to (or instead of) the synchronous one. Providing such a mechanism enables the consumer to perform resource-intensive dispose operations without blocking the main thread of a GUI application for a long time.
The IAsyncDisposable.DisposeAsync method of this interface returns a ValueTask that represents the asynchronous dispose operation. Classes that own unmanaged resources implement this method, and the consumer of these classes calls this method on an object when it is no longer needed.
Solution 2:[2]
Justin Lessard's answer explains the difference between using
and await using
, so I'll focus on which one to use. There are two cases: either the two methods Dispose
/DisposeAsync
are complementary, or they are doing something different.
If the methods are complementary, which is the common case, you can call either one of them and the result will be the same: the unmanaged resources will be released. There is no reason to call both of them, sequentially. If you do, the second call will be a no-op: the resources are already released, so there will be nothing more to do. Choosing which one to call is easy: if you are in a synchronous context, call the
Dispose()
(use theusing
). If you are in an asynchronous context, call theawait DisposeAsync()
(use theawait using
)¹.If the methods are doing something different, you should read the documentation and decide which behavior is more suitable for the scenario at hand. Let's talk for example for the
System.Threading.Timer
class, that implements both interfaces (IDisposable
andIAsyncDisposable
). TheDispose
method releases the unmanaged resources as expected, but theDisposeAsync
is doing something more than that: it also awaits the completion of any callbacks that are currently running. Let's make an experiment to demonstrate this difference:
var stopwatch = Stopwatch.StartNew();
using (new Timer(_ => Thread.Sleep(1000), null, 0, Timeout.Infinite))
{
Thread.Sleep(100);
}
Console.WriteLine($"Duration: {stopwatch.ElapsedMilliseconds:#,0} msec");
We create a timer that fires after 0 msec, so practically immediately, then we wait for 100 msec to be sure that the callback has been invoked (it is invoked on a ThreadPool
thread), and then we dispose the timer synchronously. Here is the output of this experiment:
Duration: 102 msec
Now let's switch from using
to await using
. Here is the output of the second experiment:
Duration: 1,005 msec
The implicit call to DisposeAsync
returned a ValueTask
that completed only after the completion of the timer's callback.
So in the case of a Timer
, choosing between using
and await using
is not just a choice that depends on the context. You might prefer to use the synchronous using
in an async context, because you don't care about the callback (you know that it's not harmful to let it become fire-and-forget). Or you might be in a synchronous context but you might prefer the behavior of await using
, because fire-and-forget is unacceptable. In that case you'll have to abandon the convenience of using
, and invoke instead the DisposeAsync
explicitly in a finally
block:
var timer = new Timer(_ => Thread.Sleep(1000), null, 0, Timeout.Infinite);
try { Thread.Sleep(100); }
finally { timer.DisposeAsync().AsTask().Wait(); }
¹ Be aware, especially if you are writing a library, that the await using
captures the synchronization context by default. In case this is undesirable, which usually is for library code, you'll have to configure it with ConfigureAwait(false)
. This has some implications that are discussed here: How do I get the "await using" syntax correct?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Theodor Zoulias |
Solution 2 | Theodor Zoulias |