这是一个真正的异步方法:
public Task<string> ProcessRequest()
{
var textFile = File.OpenText("file.txt");
var readTask = textFile.ReadToEndAsync();
readTask.ContinueWith(previousTask => textFile.Dispose());
return readTask;
}
如果您使用大文件或慢速驱动器上的文件运行此方法,则执行将在文件读取结束之前返回调用者很久。在 Stephen Cleary 的示例中,调用者只有在结果 ("foo") 计算完成后才能取回控制权。
Dispose 必须在 ContinueWith 中,因为方法执行将在文件读取完成之前返回给调用者,因此无法在 ProcessRequest 方法中关闭文件。
一个人当然可以开始自己的任务。
public Task<string> ProcessRequest(CancellationToken cancellationToken)
{
var readTask = Task.Run(() =>
{
using (var textFile = File.OpenText("file.txt"))
{
var text = textFile.ReadToEnd();
cancellationToken.ThrowIfCancellationRequested();
var processedText = text.Replace("foo", "bar");
return processedText;
}
});
return readTask;
}
最好有一个 CancellationToken 并定期检查是否请求取消以允许取消长时间运行的操作。
编辑 1
正如@Stephen Cleary 强调的第一个样本,这会导致大致或可能完全相同的 CIL:
public async Task<string> ProcessRequest()
{
using (var textFile = File.OpenText("file.txt"))
{
var s = await textFile.ReadToEndAsync();
return s;
}
}
基本上,编译器会将 await textFile.ReadToEndAsync() 之后的代码转换为 ContinueWith。
每种语法都有其优点,我的偏好是 1-2 行(即 dispose 和 log)进入 ContinueWith,更复杂的延续使用 await。