5
public class FooHandler  : HttpTaskAsyncHandler
{
    public override async Task ProcessRequestAsync(HttpContext context)
    {
        return await new AdRequest().ProcessRequest();
        // getting error here. "Return type of async type is void"
    }
}

public class FooRequest
{

    public async Task<String> ProcessRequest()
    {
        //return await "foo"; obviously nothing to wait here
    }

}

我想做一个异步处理程序,只想返回一个字符串。我怎样才能让这个工作?是否有使用异步方法和任务的简明参考?

4

3 回答 3

8

几点:

  • 您可以awaitany Task,而不仅仅是从async方法返回的。
  • async方法将它们的返回值包装成Task<TResult>; 如果没有返回值,它们会将返回值本身包装到一个Task.
  • 有几种方便的方法可用,例如,Task.FromResult如果您不需要async方法的开销。
  • 仅在async必须使用方法时才创建方法await。如果您不需要制作方法async,请不要。

你可能会发现我的async/await 介绍很有帮助。

public class FooHandler  : HttpTaskAsyncHandler
{
  public override Task ProcessRequestAsync(HttpContext context)
  {
    return new AdRequest().ProcessRequest();
  }
}

public class AdRequest
{
  public Task<String> ProcessRequest()
  {
    return Task.FromResult("foo");
  }
}
于 2012-08-09T10:34:30.497 回答
1

您不应该“返回”任务,编译器会隐式执行它,因为它是一个异步函数:

public override async Task ProcessRequestAsync(HttpContext context)
{
    await new AdRequest().ProcessRequest();
}

public async Task<String> ProcessRequest()
{
    return "foo";
}

这是另一种方式,更接近您尝试做的事情:(没有异步/等待)

public override Task ProcessRequestAsync(HttpContext context)
{
    return new AdRequest().ProcessRequest();
}

public Task<String> ProcessRequest()
{
    return Task.Return("foo");
}

一般参考asynchere 本质上将async修饰符添加到方法中,使其Task隐式返回。如果您返回一个 int,它将把它变成一个Task<int>. await反之,将 aTask<int>变成int.

于 2012-08-09T08:34:29.037 回答
0

这是一个真正的异步方法:

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。

于 2015-01-09T14:58:35.307 回答