如何在C#async http库中管理大量委托和用户回调

时间:2011-01-02 10:08:35

标签: c# .net xbmc

我在C#中编写一个.NET库,用于通过其JSON RPC接口使用HTTP与XBMC进行通信。

我编码并发布了preliminary version,但所有内容都是同步完成的。然后,当我正在/正在构建XBMC remote for WP7时,我将库重新编码为异步,我正在构建{{3}}。

我现在想要发布新的异步库,但想要确保它在我做之前很好又整洁。

由于用户发起请求的异步性质,提供与我的委托匹配的回调方法,然后在收到响应后处理响应。

我遇到的问题是在库中我跟踪RequestState对象的请求生命周期,它包含http请求/响应以及用户回调等作为成员变量,如果只有一个,这将是好的对象的类型回来了,但根据用户的呼叫,他们可能会返回歌曲列表或电影列表等。

我的实现目前使用单个委托ResponseDataRecieved,它有一个参数,它是一个简单的对象 - 因为我只知道哪些方法返回什么,当我处理响应时,我将所述对象转换为类型我知道它确实是 - 列表,列表等

第三方不应该这样做 - 委托签名应包含正确类型的对象。那么我需要一个可以返回给第三方的每种类型的响应数据的委托 - 具体问题是,我如何在内部优雅地处理这个问题 - 我是否有一堆不同的RequestState对象,每个对象都有一个不同的成员变量对于不同的代表?这并不“感觉”正确。我只是不知道如何优雅而干净地做到这一点。

2 个答案:

答案 0 :(得分:0)

如果我理解正确,你有一个提供多个方法的接口,每个方法基本上采用相同类型的委托,但获取不同类型的参数作为输入。像这样:

GetListOfSongs(..., delegate(List<Song> result) { ... });
GetListOfMovies(..., delegate(List<Movie> result) { ... });

您是否担心与界面中的方法一起开始出现的委托签名?

如果是这种情况,那么泛型就是您正在寻找的东西。实际上,如果您的委托签名与我的示例匹配 - 也就是说,接受一个输入参数,则不返回任何值 - 您想要的委托类型已经存在于BCL中。它被称为Action<T>。你可以像这样声明上面的方法:

GetListOfSongs(..., Action<List<Song>> callback);
GetListOfMovies(..., Action<List<Movie>> callback);

并且您仍然只有一个委托类型,即Action<T>

现在,如果您需要传递多个参数,那么您仍然可以使用。存在最多16个输入参数的Action版本(虽然它们的签名看起来有点花哨:Action<T1, T2, T3 ...>)。

如果您希望回调也返回一个您将在基础结构中使用的值,Func<T, TResult>是您的朋友(T是输入参数的类型,TResult是您将要使用的值的类型从代表处返回。)

作为奖励,我建议您不要在界面中公开List<T>。如果您确实认为所有客户都需要列表操作,请使用IList<T>,但如果不这样做,请考虑ICollection<T>甚至IEnumerable<T>

答案 1 :(得分:0)

首先想到的是泛型:ResponseDataRecieved<T>其中T是回调中预期的类型。但是,您可以将回调保存为捕获的变量。例如:

public delegate void CallBackA(int i);
public delegate void CallBackB(string s);

public class RequestHandler
{
    public void QueueRequestA(CallBackA callback)
    {
        Task.Factory.StartNew(() =>
                                  {
                                      int ret = 0;
                                      //ret = get stuff of type A from server
                                      callback(ret); //callback is captured here
                                  });
    }

    public void QueueRequestB(CallBackB callback)
    {
        Task.Factory.StartNew(() =>
                                  {
                                      string str = "";
                                      //str = get stuff of typw B from server
                                      callback(str); //callback is captured here
                                  });
    }
}