3

我有一个从 url 获取 HTML,通过解析提取实体并返回实体列表的方法。这是示例代码:

  public List<Entity> FetchEntities()
    {
        List<Entity> myList = new List<Entity>();
        string url = "<myUrl>";
        string response = String.Empty;
        client = new WebClient();
        client.DownloadStringCompleted += (sender, e) =>
        {
            response = e.Result;
            // parse response
            // extract content and generate entities
            // <---- I am currently filling list here
        };
        client.DownloadStringAsync(new Uri(url));

        return myList;
    }

问题是当异步调用正在进行时,控制返回时为空myList。我该如何防止这种情况。我的最终目标是返回填充列表。

而且这个方法也在一个单独的类库项目中,并从 Windows Phone 应用程序中调用,我必须保持这样。有什么办法可以做到这一点,或者我错过了什么?任何帮助将不胜感激。

4

2 回答 2

4

这就是异步编程的要点是非阻塞的。您可以将回调作为参数传递并在其他地方处理结果,而不是尝试返回它。

如果您需要返回结果,您可以使用这个 TPL 库,我已经使用它一段时间了。

public Task<string> GetWebResultAsync(string url)
     {
         var tcs = new TaskCompletionSource<string>();
         var client = new WebClient();

         DownloadStringCompletedEventHandler h = null;
         h = (sender, args) =>
                 {
                     if (args.Cancelled)
                     {
                         tcs.SetCanceled();
                     }
                     else if (args.Error != null)
                     {
                         tcs.SetException(args.Error);
                     }
                     else
                     {
                         tcs.SetResult(args.Result);
                     }

                     client.DownloadStringCompleted -= h;
                 };

         client.DownloadStringCompleted += h;
         client.DownloadStringAsync(new Uri(url));

         return tcs.Task;
     }
}

调用它正是您在 .net 4.0 中使用 TPL 的方式

GetWebResultAsnyc(url).ContinueWith((t) => 
                                    {
                                         t.Result //this is the downloaded string
                                    });

或者:

var downloadTask = GetWebResultAsync(url);
downloadTask.Wait();
var result = downloadTask.Result; //this is the downloaded string

希望这可以帮助 :)

于 2013-01-12T07:08:06.840 回答
4

您可以像这样将回调传递给方法,并使其在没有任务的情况下异步,因此您必须稍微更新方法的使用。

public void FetchEntities(
    Action<List<Entity>> resultCallback, 
    Action<string> errorCallback)
{
    List<Entity> myList = new List<Entity>();
    string url = "<myUrl>";
    string response = String.Empty;
    client = new WebClient();
    client.DownloadStringCompleted += (sender, e) =>
    {
        response = e.Result;
        // parse response
        // extract content and generate entities
        // <---- I am currently filling list here

        if (response == null)
        {
            if (errorCallback != null)
                errorCallback("Ooops, something bad happened");
        }
        else
        {
            if (callback != null)
                callback(myList);
        }
    };
    client.DownloadStringAsync(new Uri(url));
}

另一种选择是强制它同步。像那样

public List<Entity> FetchEntities()
{
    List<Entity> myList = new List<Entity>();
    string url = "<myUrl>";
    string response = String.Empty;
    client = new WebClient();
    AutoResetEvent waitHandle = new AutoResetEvent(false);
    client.DownloadStringCompleted += (sender, e) =>
    {
        response = e.Result;
        // parse response
        // extract content and generate entities
        // <---- I am currently filling list here

        waitHandle.Set();
    };
    client.DownloadStringAsync(new Uri(url));

    waitHandle.WaitOne();

    return myList;
}
于 2013-01-12T09:37:42.247 回答