Szy*_*iga 2 c# events asynchronous webclient windows-phone-7
我有一个JSON API,我希望我的应用程序访问.所以我写了一个方法.
public List<Books> GetBooks()
{
  var webclient = new WebClient();
  var jsonOutput = webclient.DownloadString(
                         new Uri("http://someplace.com/books.json")
                             );
  return ParseJSON(jsonOutput);//Some synchronous parsing method 
}
现在我需要将DonwloadString更改为DownloadStringAsync.我找到了这个教程.
但这似乎太复杂了.我试图让这个工作,但我不确定这是否是正确的方法.也许有一种更简单,更好的方法?
所有要求您订阅事件以获取结果的异步操作都很痛苦.我认为最简单的方法是将事件处理抽象为一些很好的扩展方法,并使用连续传递样式(CPS)来处理结果.
所以,首先要创建一个下载字符串的扩展方法:
public static void DownloadString(this Uri uri, Action<string> action)
{
    if (uri == null) throw new ArgumentNullException("uri");
    if (action == null) throw new ArgumentNullException("action");
    var webclient = new WebClient();
    DownloadStringCompletedEventHandler handler = null;
    handler = (s, e) =>
    {
        var result = e.Result;
        webclient.DownloadStringCompleted -= handler;
        webclient.Dispose();
        action(result);
    };
    webclient.DownloadStringCompleted += handler;
    webclient.DownloadStringAsync(uri);
}
这种方法隐藏了的创作WebClient,所有的事件处理,以及部署和退订事后清理的东西了.
它的使用方式如下:
var uri = new Uri("http://someplace.com/books.json");
uri.DownloadString(t =>
{
    // Do something with the string
});
现在,这可用于创建GetBooks方法.这里是:
public void GetBooks(Uri uri, Action<List<Books>> action)
{
    if (action == null) throw new ArgumentNullException("action");
    uri.DownloadString(t =>
    {
        var books = ParseJSON(t);
        action(books);
    });
}
它的使用方式如下:
this.GetBooks(new Uri("http://someplace.com/books.json"), books =>
{
    // Do something with `List<Books> books`
});
那应该是整洁而简单的.
现在,您可能希望通过以下两种方式扩展它.
您可以创建ParseJSON具有此签名的重载:
void ParseJSON(string text, Action<List<Books>> action)
然后你可以完全取消这个GetBooks方法,然后写下:
var uri = new Uri("http://someplace.com/books.json");
uri.DownloadString(t => ParseJSON(t, books =>
{
    // Do something with `List<Books> books`
    // `string t` is also in scope here
}));
现在你有一个漂亮的流畅风格,可组合的操作集.作为奖励,下载的字符串t也在范围内,因此您可以轻松地记录它或者在需要时进行其他处理.
您可能还需要处理异常,这些可以像这样添加:
public static void DownloadString(
    this Uri uri,
    Action<string> action,
    Action<Exception> exception)
{
    if (uri == null) throw new ArgumentNullException("uri");
    if (action == null) throw new ArgumentNullException("action");
    var webclient = (WebClient)null;
    Action<Action> catcher = body =>
    {
        try
        {   
            body();
        }
        catch (Exception ex)
        {
            ex.Data["uri"] = uri;
            if (exception != null)
            {
                exception(ex);
            }
        }
        finally
        {
            if (webclient != null)
            {
                webclient.Dispose();
            }
        }
    };
    var handler = (DownloadStringCompletedEventHandler)null;        
    handler = (s, e) =>
    {
        var result = (string)null;
        catcher(() =>
        {   
            result = e.Result;
            webclient.DownloadStringCompleted -= handler;
        });
        action(result);
    };
    catcher(() =>
    {   
        webclient = new WebClient();
        webclient.DownloadStringCompleted += handler;
        webclient.DownloadStringAsync(uri);
    });
}
然后,您可以将非错误处理DownloadString扩展方法替换为:
public static void DownloadString(this Uri uri, Action<string> action)
{
    uri.DownloadString(action, null);
}
然后使用错误处理方法,你会这样做:
var uri = new Uri("http://someplace.com/books.json");
uri.DownloadString(t => ParseJSON(t, books =>
{
    // Do something with `List<Books> books`
}), ex =>
{
    // Do something with `Exception ex`
});
最终结果应该相当简单易用和阅读.我希望这有帮助.