I have the following synchronous code, which works fine:
private void GenerateExportOutput()
{
using StreamWriter writer = new(Coordinator.OutputDirectory + @"\export.txt");
if (this.WikiPagesToExport.IsEmpty)
{
return;
}
var wanted = new SortedDictionary<string, WikiPage>(this.WikiPagesToExport, StringComparer.Ordinal);
foreach (var title in wanted.Keys)
{
writer.WriteLine(title);
}
}
I want to change it to be asynchronous. So:
private async Task GenerateExportOutputAsync()
{
using StreamWriter writer = new(Coordinator.OutputDirectory + @"\export.txt");
if (this.WikiPagesToExport.IsEmpty)
{
return;
}
var wanted = new SortedDictionary<string, WikiPage>(this.WikiPagesToExport, StringComparer.Ordinal);
foreach (var title in wanted.Keys)
{
await writer.WriteLineAsync(title).ConfigureAwait(false);
}
await writer.FlushAsync().ConfigureAwait(false);
}
Which compiles. But one of the analyzers I use (Meziantou.Analyzer) now suggests that I "prefer using 'await using'". I've never used await using (though I've tried several times in the past and have always run into the same problems I'm running into now). But I would like to use it, so:
await using StreamWriter writer = new StreamWriter(OutputDirectory + @"\export.txt").ConfigureAwait(false);
Now it no longer compiles: CS0029 Cannot implicitly convert type 'System.Runtime.CompilerServices.ConfiguredAsyncDisposable' to 'System.IO.StreamWriter'
. OK, fine, so I change it to use var
instead:
await using var writer = new StreamWriter(OutputDirectory + @"\export.txt").ConfigureAwait(false);
Which gets it past the CS0029, but now the later code doesn't compile: Error CS1061 'ConfiguredAsyncDisposable' does not contain a definition for 'WriteLineAsync'
(and a similar one for FlushAsync
. Soooo... maybe cast it?
await ((StreamWriter)writer).WriteLineAsync(title).ConfigureAwait(false);
Nope: Error CS0030 Cannot convert type 'System.Runtime.CompilerServices.ConfiguredAsyncDisposable' to 'System.IO.StreamWriter'
I've googled a bunch and read a bunch, both now and several times in the past, but I just have been completely unable to figure out how to use this "await using" thing. How can I do so? Thanks.
The await using
syntax currently (C# 10) leaves a lot to be desired, regarding its support for configuring the awaiting of IAsyncDisposable
s. The best we can do is this:
private async Task GenerateExportOutputAsync()
{
StreamWriter writer = new(Coordinator.OutputDirectory + @"\export.txt");
await using (writer.ConfigureAwait(false))
{
//...
}
}
...which doesn't prevent us from using the writer
variable outside of the await using
section by mistake, and it's not really much more compact than not using the await using
syntax at all:
private async Task GenerateExportOutputAsync()
{
StreamWriter writer = new(Coordinator.OutputDirectory + @"\export.txt");
try
{
//...
}
finally { await writer.DisposeAsync().ConfigureAwait(false); }
}
Related GitHub issue: Using ConfigureAwait in "await using" declaration.