Home > front end >  Do I need to call DisposeAsync on a FileStream when using it with using clause?
Do I need to call DisposeAsync on a FileStream when using it with using clause?

Time:01-13

Consider the following code taken from the the Microsoft docs:

using FileStream createStream = File.Create(fileName);
// ...write to stream etc..
await createStream.DisposeAsync(); // <- isn't this done automatically because of the using clause in the first line`?

Isn't calling the DisposeAsync() method superfluous?

CodePudding user response:

using clause will call Dispose() method, not DisposeAsync(). It's not the same since Dispose() is blocking call and the presence of DisposeAsync suggests that dispose might be resource intensive and so you don't want to call Dispose if you can instead call DisposeAsync.

The code as written will first call DisposeAsync and then at the end of the scope it will also call Dispose. We can assume it's harmless because implementing class should have a check that resource was already disposed so second Dispose should do nothing. However, if you use C#8 , you can use await using:

await using FileStream createStream = File.Create(fileName);

This is the same as using but it will call await DisposeAsync() at the end of the scope, instead of Dispose. So just like you do now, but automatically (and in finally block). It works with IAsyncDisposable target (such as FileStream which inherits from Stream which implements IAsyncDisposable).

CodePudding user response:

You need to check the whole snippet here:

public static async Task Main()
{
    var weatherForecast = new WeatherForecast
    {
        // ...
    };

    string fileName = "WeatherForecast.json";
    using FileStream createStream = File.Create(fileName);
    await JsonSerializer.SerializeAsync(createStream, weatherForecast);
    await createStream.DisposeAsync();

    Console.WriteLine(File.ReadAllText(fileName));
}

using declaration will call Dispose in generated finally block at the end of the current scope, the problem here is that the file is accessed before the end of the scope:

Console.WriteLine(File.ReadAllText(fileName));

So the await createStream.DisposeAsync(); is actually needed otherwise the file will not be accessible (or even if it would be - potentially not all data will be flushed).

In this concrete case switching to using statement (the one with braces, also both using statement and declaration actually support handling IAsyncDisposable) would be cleaner and will make await createStream.DisposeAsync(); call redundant:

await using (FileStream createStream = File.Create(fileName))
{
    await JsonSerializer.SerializeAsync(createStream, weatherForecast);
}

Console.WriteLine(File.ReadAllText(fileName));
  • Related