开发者

How to manage large amounts of delegates and usercallbacks in C# async http library

I'm coding a .NET library in C# for communicating with XBMC via its JSON RPC interface using HTTP.

I coded and released a preliminary version but everything is done synchronously. I then recoded the library to be asynchronous for my own purposes as I was/am building an XBMC remote for WP7.

I now want to release the new async library but want to make sure it's nice and tidy before I do.

Due to the async nature a user initiates a request, supplies a callback method that matches my delegate and then handles the response once it's been received.

The problem I have is that within the library I track a RequestState object for the lifetime of the request, it contains the http request/response as well as the user callback etc. as member variables, this would be fine if only one type of object was coming back but depending on what the user calls they may be returned a list of songs or a list开发者_开发知识库 of movies etc.

My implementation at the moment uses a single delegate ResponseDataRecieved which has a single parameter which is a simple Object - As this has only be used by me I know which methods return what and when I handle the response I cast said object to the type I know it really is - List, List etc.

A third party shouldn't have to do this though - The delegate signature should contain the correct type of object. So then I need a delegate for every type of response data that can be returned to the third party - The specific problem is, how do I handle this gracefully internally - Do I have a bunch of different RequestState objects that each have a different member variable for the different delegates? That doesn't "feel" right. I just don't know how to do this gracefully and cleanly.


If I understood you correctly, you have an interface that provides multiple methods, each of which takes basically the same kind of delegate, but gets a different type of parameter as input. Something like this:

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

and you're worried about the delegate signatures that start cropping up along with the methods in the interface?

If that's the case, then generics are what you're looking for. In fact, if your delegate signature matches my example -- that is, accepts one input parameter, returns no value -- the delegate type you want already exists in the BCL. It's called Action<T>. You could declare the methods above like so:

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

and you'd still only have a single delegate type, that is, Action<T>.

Now, if you need to pass along more than one parameter, you're still covered. There exist versions of Action for up to 16 input parameters (although their signatures begin to look a bit garish: Action<T1, T2, T3 ...>).

If you want your callback to also return a value that you'll use somewhere within your infrastructure, Func<T, TResult> is your friend (T is the type of the input parameter, TResult is the type of the value you will return from the delegate).

As a bonus, I'd recommend you don't expose List<T> in your interfaces. If you really think all your clients will need list operations, use IList<T>, but consider ICollection<T> or even IEnumerable<T> if they won't.


The first thing that comes to mind is generics: ResponseDataRecieved<T> where T is the type expected in the callback. However, you could save the callbacks as captured variables. For example:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜