IAsyncDisposable, using statements, and async/await
See original GitHub issueWith the introduction of support for await
inside of a finally
block, I’d like to propose the following extension to the using
statement in C#.
The System.IAsyncDisposable
interface
public interface IAsyncDisposable : IDisposable
{
Task DisposeAsync();
}
Modification to the using
statement
When a using
statement appears inside of an async
method, the translation of the using
statement is modified to the following.
A using
statement of the form
using (ResourceType resource = expression) statement
corresponds to one of four possible expansions. When ResourceType
is a non-nullable value type which implements System.IAsyncDisposable
, the expansion is
{
ResourceType resource = expression;
try {
statement;
}
finally {
await ((IAsyncDisposable)resource).DisposeAsync();
}
}
Otherwise, when ResourceType
is a non-nullable value type which does not implement System.IAsyncDisposable
, the expansion is
{
ResourceType resource = expression;
try {
statement;
}
finally {
((IDisposable)resource).Dispose();
}
}
Otherwise, when ResourceType
is a nullable value type or a reference type other than dynamic
, the expansion is:
{
ResourceType resource = expression;
try {
statement;
}
finally {
if (resource != null) {
IAsyncDisposable tmp = resource as IAsyncDisposable;
if (tmp != null) {
await tmp.DisposeAsync();
}
else {
((IDisposable)resource).Dispose();
}
}
}
}
Otherwise, when ResourceType
is dynamic
, the expansion is
{
ResourceType resource = expression;
IDisposable d = (IDisposable)resource;
try {
statement;
}
finally {
if (d != null) {
IAsyncDisposable tmp = d as IAsyncDisposable;
if (tmp != null) {
await tmp.DisposeAsync();
}
else {
d.Dispose();
}
}
}
}
The IAsyncDisposable
interface has no impact on the expansion of using
statements which appear in any context other than a method marked with the async
modifier.
Issue Analytics
- State:
- Created 9 years ago
- Reactions:41
- Comments:77 (34 by maintainers)
Top GitHub Comments
I find it scary that there’ll be an implicit “await” in your code (i.e. re-entrancy vulnerability) with no indication of it in your code. Could you tell me your thoughts on a compound keyword?
@mlehmk That only works if Dispose has no observable behavior.
Pretend you implement that logic in FileStream that you’ve opened for exclusive access to a file, that you want to delete that immediately afterwards after disposing the FileStream. How would you know when you can delete the file?