2015-05-20 3 views
1

Я новичок в Rx в .net, но начали использовать его с некоторым успехом подведению некоторых Коммуникационная сетьRX IObserver подписки времени

Очень упрощенный пример:

IObservable<Result> SendRequest(Request request) 
    { 
     return Observable.Create<Result>(observer => 
     { 
      NetworkComms.SendReqeust(request, 
       result => 
       { 
        observer.OnNext(result); 
        observer.OnCompleted(); 
       }); 
      return Disposable.Empty; 
     }).SubscribeOn(_commsScheduler); 
    } 

Проблема у меня есть заключается в том, что команда (NetworkComms.SendRequest) фактически не отправляется до тех пор, пока вызывающий абонент не присоединится к возвращенному IObservable. В некоторых случаях запрос является командой «огонь-и-забыть», и результат довольно бессмыслен, поэтому для абонента не имеет смысла фактически подписываться на возвращаемый IObservable.

функциональность мне нужно:

  1. Команда отправляется немедленно, даже если абонент никогда не присоединяется к IObservable
  2. Если и когда клиент выписывает, они получат результат, даже если они поздняя подписка
  3. Команда отправляется только один раз, но все подписки должны получать одинаковые результаты.

Я попытался сделать это с использованием .Replay(). RefCount() и выполнить функцию Subscribe() перед возвратом IObservable. Это почти работает, но в том случае, когда клиент подписывает после результат, полученный (и, следовательно, после автоматического удаления последовательности после завершения), он вызывает повторный вызов кода подписки, отправляя команду во второй раз.

Есть ли простое расширение Rx, которое может справиться с этим сценарием для меня, или мне нужно катиться самостоятельно?

+0

Это действительно странно, что сочинять это наблюдаемое. Вы говорите, что я буду запускать этот запрос время от времени до конца времени (или когда приложение закрывается) вернет мне результат, независимо от того, насколько он прост. – Enigmativity

+0

Вы также не должны делать 'return Disposable.Empty;'. Если вы когда-либо делаете это, вы, вероятно, совершаете ошибку - вы обычно делаете блокирующую подписку (какая вы есть). Вам лучше вернуть подписку на «Observable.Start (() => {...}). Подписаться (observer)'. – Enigmativity

ответ

4

Похоже, что вы хотите использовать AsyncSubject<T>:

IObservable<Result> SendRequest(Request request) 
{ 
    var subject = new AsyncSubject<Result>(); 
    NetworkComms.SendReqeust(request, result => 
    { 
     subject.OnNext(result); 
     subject.OnCompleted(); 
    }); 
    return subject.AsObservable(); 
} 

Я хотел бы добавить, что интерфейс вы хотите немного странно. Если семантика - это «В тот момент, когда я вызываю этот метод, запрос делается, и любой, кто хочет получить ответ позже», тогда рассмотрим только использование Task<Result> вместо IObservable<Result>.

Task<Result> SendRequestAsync(Request request) 
{ 
    var tcs = new TaskCompletionSource<Result>(); 
    NetworkComms.SendReqeust(request, result => tcs.SetResult(result)); 
    return tcs.Task; 
} 

Кроме того, рассмотреть вопрос о создании этого Task<Result> SendRequestAsync(Request request) метод непосредственно на NetworkComms класса.

+0

Ах, спасибо за это. Я видел классы Subject, но материал, который я читал, сказал, что их не следует использовать в производственном коде, поэтому я не стал их рассматривать дальше. Похоже, это путь. Основная точка нечетного интерфейса - так, что действие происходит, даже если результаты не подписаны, но если результаты подписываются (даже после того, как действие завершено), результаты все равно будут получены. Это не ожидаемый сценарий, что результаты будут подписаны более одного раза, но я хотел бы четко сказать, что это не повторит действие только для полноты. – Andy

+1

@Andy (примечание, которое я отредактировал, чтобы использовать 'AsyncSubject ' вместо 'ReplaySubject ' - первый здесь более уместен, потому что последовательность содержит только одно значение.) «Объекты не должны использоваться в производственном коде» - это радикальное заявление. Причина, по которой люди не любят предметы, состоит в том, что они являются состояниями. Но если вам нужно сделать что-то сдержанное, они подходят. Просто будьте осторожны с их использованием. (См. Мое предложение в последнем абзаце об альтернативе.) –

+1

@Andy Подписывание возвращаемому наблюдаемому несколько раз не будет вызывать сетевой вызов несколько раз. Подписка не имеет побочных эффектов. Вызов SendRequestAsync имеет все побочные эффекты. –

Смежные вопросы