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

いくつかのポイント:

  • メソッドから返されたものだけでなく、await任意の を使用できます。Taskasync
  • asyncTask<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

Task を「返す」べきではありません。非同期関数であるため、コンパイラは暗黙的にそれを行います。

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");
}

への一般的な参照asyncここにあります 基本的にasync修飾子をメソッドに追加すると、Task暗黙的に が返されます。int を返すと、それは に変わりますTask<int>awaitは反対のことを行い、 a を に変えTask<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") の計算が終了したときにのみ制御を取り戻します。

ファイルの読み取りが完了する前にメソッドの実行が呼び出し元に戻るため、ProcessRequest メソッドでファイルを閉じることができないため、Dispose は ContinueWith にある必要があります。

もちろん、自分のタスクを開始することもできます。

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 に入り、より複雑な継続の使用が待っていることです。

于 2015-01-09T14:58:35.307 に答える