Как управлять большим количеством делегатов и обратных вызовов пользователей в C # async http library - PullRequest
0 голосов
/ 02 января 2011

Я пишу библиотеку .NET на C # для связи с XBMC через JSON RPC-интерфейс с использованием HTTP.

Я кодировал и выпустил предварительную версию , но все делается синхронно. Затем я перекодировал библиотеку, чтобы она была асинхронной для моих собственных целей, поскольку я строил / собираю XBMC remote для WP7 .

Теперь я хочу выпустить новую асинхронную библиотеку, но хочу убедиться, что она хороша и опрятна, прежде чем я это сделаю.

Из-за асинхронной природы пользователь инициирует запрос, предоставляет метод обратного вызова, соответствующий моему делегату, а затем обрабатывает ответ после его получения.

Проблема, с которой я столкнулся, заключается в том, что в библиотеке я отслеживаю объект RequestState в течение всего времени существования запроса, он содержит запрос / ответ http, а также обратный вызов пользователя и т. Д. В качестве переменных-членов, это было бы хорошо, если бы только один тип объекта возвращался, но в зависимости от того, что пользователь называет, ему может быть возвращен список песен или список фильмов и т. д.

Моя реализация в настоящий момент использует один делегат ResponseDataRectained, у которого есть единственный параметр, который является простым объектом. Поскольку это используется только мной, я знаю, какие методы возвращают то, что и когда я обрабатываю ответ, я приводил указанный объект к Я знаю, что это действительно так - Список, Список и т. д.

Третья сторона не должна этого делать - подпись делегата должна содержать правильный тип объекта. Итак, мне нужен делегат для каждого типа данных ответа, которые могут быть возвращены третьей стороне. Конкретная проблема заключается в том, как я могу обработать это изящно внутренне. Есть ли у меня куча различных объектов RequestState, каждый из которых имеет свою переменную-член для разных делегатов? Это не "чувствовать" правильно. Я просто не знаю, как это сделать изящно и чисто.

Ответы [ 2 ]

0 голосов
/ 03 января 2011

Первое, что приходит на ум - это дженерики: 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
                                  });
    }
}
0 голосов
/ 02 января 2011

Если я вас правильно понял, у вас есть интерфейс, который предоставляет несколько методов, каждый из которых принимает в основном один и тот же тип делегата, но получает входной параметр другого типа. Примерно так:

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>.

Теперь, если вам нужно передать более одного параметра, вы все равно охвачены. Существуют версии Action для 16 входных параметров (хотя их сигнатуры начинают выглядеть немного странно: Action<T1, T2, T3 ...>).

Если вы хотите, чтобы ваш обратный вызов также возвращал значение, которое вы будете использовать где-то в вашей инфраструктуре, Func<T, TResult> - ваш друг (T - тип входного параметра, TResult - тип значения, которое вы будете возвращать делегат).

В качестве бонуса я бы порекомендовал вам не выставлять List<T> в своих интерфейсах. Если вы действительно думаете, что все ваши клиенты будут нуждаться в операциях со списком, используйте IList<T>, но рассмотрите ICollection<T> или даже IEnumerable<T>, если они не будут.

...