weston weston - 11 days ago 6
C# Question

Tail call async without await

Take this

async
method:

public async Task<string> ReadStringFromUrlAsync(string url)
{
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
var reader = new StreamReader(dataStream);
return await reader.ReadToEndAsync();
}


Because it returns the result of another task I believe I can do away with
async
and
await
:

public Task<string> ReadStringFromUrlAsync(string url)
{
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
var reader = new StreamReader(dataStream);
return reader.ReadToEndAsync();
}


I noticed that the call stack in the event of an exception won't mention
ReadStringFromUrlAsync
, are there any other drawbacks to removing
aysnc
/
await
on tail calls in this way.

Answer

It's fine in most cases, but there is an important difference in exception behavior: any exceptions before the task is returned will be thrown directly rather than placed on the task. In your example, if WebRequest.Create, GetResponse, GetResponseStream, or StreamReader(..) throws, then in an async method that exception would be placed on the task, while in a non-async method that exception would be thrown directly.

BTW, if that's representative of your real code, I'd recommend using HttpClient instead, which was designed with await in mind:

public Task<string> ReadStringFromUrlAsync(string url)
{
  return new HttpClient().GetStringAsync(url);
}
Comments