.net 在使用using子句时,是否需要在FileStream上调用DisposeAsync?

k2arahey  于 2023-01-14  发布在  .NET
关注(0)|答案(2)|浏览(126)

考虑以下取自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`?

调用DisposeAsync()方法不是多余的吗?

lkaoscv7

lkaoscv71#

using子句将调用Dispose()方法,而不是DisposeAsync()。这是不一样的,因为Dispose()正在阻塞调用,并且DisposeAsync的存在表明dispose可能占用大量资源,因此如果可以调用DisposeAsync,则不希望调用Dispose
编写的代码将首先调用DisposeAsync,然后在作用域的末尾调用Dispose。我们可以假设这是无害的,因为实现类应该检查资源是否已经被释放,因此第二个Dispose不应执行任何操作。但是,如果您使用C#8+,则可以使用await using

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

这与using相同,但它将在作用域的末尾调用await DisposeAsync(),而不是Dispose。因此,就像您现在所做的一样,但自动(并在finally块中)。它使用IAsyncDisposable目标(例如FileStream,它继承自Stream,后者实现IAsyncDisposable)。

i7uaboj4

i7uaboj42#

你需要检查整个片段在这里:

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声明将在当前作用域的末尾调用generated finally块中的Dispose,这里的问题是文件在作用域结束之前被访问:

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

因此,实际上需要await createStream.DisposeAsync();,否则文件将无法访问(或者即使可以访问,也可能不会刷新所有数据)。
在这个具体的例子中,切换到using statement(带大括号的using statement,而且using语句和声明实际上都支持处理IAsyncDisposable)会更简洁,并且会使await createStream.DisposeAsync();调用变得冗余:

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

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

相关问题