1. ホーム
  2. c#

ボタンクリックで非同期メソッドを呼び出す

2023-10-04 13:38:58

質問

Windows Phone 8.1 プロジェクトを作成しました。 async メソッド GetResponse<T>(string url) を実行し、メソッドが終了するのを待ちますが、メソッドが終了することはありません。以下は私のコードです。

private void Button_Click(object sender, RoutedEventArgs 
{
      Task<List<MyObject>> task = GetResponse<MyObject>("my url");
      task.Wait();
      var items = task.Result; //break point here
}

public static async Task<List<T>> GetResponse<T>(string url)
{
    List<T> items = null;
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);

    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
    try
    {
        Stream stream = response.GetResponseStream();
        StreamReader strReader = new StreamReader(stream);
        string text = strReader.ReadToEnd();
        items = JsonConvert.DeserializeObject<List<T>>(text);
    }
    catch (WebException)
    {
        throw;
    }
    return items;
}

にぶら下がります。 task.Wait() .

ボタンのクリックメソッドを async に変更し await の前に async メソッドを呼び出すと、その結果 ( await GetResponse<string>("url") ). 何が問題なのかというと Task<List<string>> task = GetResponse<string>("url") ? 私は何を間違えているのでしょうか?

助けてくれてありがとうございます。

どのように解決するのですか?

あなたは古典的なデッドロックの犠牲者です。 task.Wait() または task.Result はUIスレッドのブロック呼び出しで、デッドロックの原因となります。

UIスレッドでブロックしない . 絶対にしないでください。ただ await にしてください。

private async void Button_Click(object sender, RoutedEventArgs 
{
      var task = GetResponseAsync<MyObject>("my url");
      var items = await task;
}

ところで、なぜ WebException をキャッチして投げ返しているのでしょうか?単にキャッチしない方が良いのでは?どちらも同じです。

の中で、非同期コードと同期コードを混ぜているのもわかります。 GetResponse メソッド内で非同期コードと同期コードを混在させていることがわかります。 StreamReader.ReadToEnd はブロッキングコールです。 StreamReader.ReadToEndAsync .

また、TAP("Task based Asynchronous Pattern")に従い、タスクや非同期を返すメソッドには"Async" を付けてください。 Jonのコメント .

上記の懸念事項をすべて解決したら、あなたのメソッドは次のようになるはずです。

public static async Task<List<T>> GetResponseAsync<T>(string url)
{
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);

    Stream stream = response.GetResponseStream();
    StreamReader strReader = new StreamReader(stream);
    string text = await strReader.ReadToEndAsync();

    return JsonConvert.DeserializeObject<List<T>>(text);
}