2015-05-15 2 views
0

В Rx существует три основных метода: OnNext<T>, OnError и OnComplete, и только OnNext должен передавать данные.Использование исключения в качестве объекта передачи данных в реактивных расширениях

У меня есть данные с точками времени и данными, когда есть нормальные значения, которые передаются через OnNext и учитывают более 99% точек данных. Но тогда некоторые точки данных являются исключительными, например. отложенные данные или неточные данные, которые переписывают историю. Логично следующее: Событие по данным, требующим специального лечения, но не следующие данные в ожидаемом порядке.

«Нормально» в этом случае передавать исключительные значения через канал OnError? Я мог бы определить OutOfOrderDataExcpetion<T> : Exception с свойством типа T и обработать его в наблюдателе. Учитывая, что исключительные значения являются редкими, и я не делаю исключения/создания исключений, но создаю их и использую их как DTO, производительность не должна быть проблемой.

Меня беспокоит то, что метод называется OnError, а не OnException, но мои данные не являются ошибкой, ему просто нужна специальная обработка. В то же время, если я выставляю свой наблюдаемый внешний код, который ничего не знает о OutOfOrderExcpetion<T>, внешний код не сможет его поймать, и это будет ошибкой.

Я мог бы следить за шаблоном поиска событий и обернуть каждое событие данных в оболочку с помощью команды и полезной нагрузки, но тогда мне нужно будет распаковать каждую команду, а в 99% + случаях она будет той же командой «next». Использование OnError в качестве канала для всех остальных команд дает мне почти тот же шаблон источника событий с упрощенной обработкой.

Помимо проблемы с именами, не могли бы вы добавить некоторые аргументы, которые помешают мне использовать этот дизайн? Или это правильное использование исключений?

ответ

2

Существует договор о поведении для наблюдаемых значений Rx. Вам гарантируется ноль или более OnNext звонков, а затем один и только один из OnError или OnCompleted.

Если вы используете OnError, тогда вы говорите, что «что-то пошло не так, и теперь последовательность закончилась».

Таким образом, вы действительно не можете использовать OnError, поскольку это не «канал ошибки».

Было бы просто использовать обертку, если вы сделали это таким образом:

normals 
    .Select(data => new { normal = true, data }) 
    .Merge(
     specials 
      .Select(data => new { normal = false, data }) 
+0

Это очень хороший момент, что OnError может быть «одним и единственным», спасибо! У вас есть ссылка на документы? И если «нормальные» потребители следуют спецификациям, они прекратятся и отпишутся и не будут видеть следующую ошибку, что именно проблема с «специальными подписчиками», которая выдержит особые исключения? –

+0

В [MSDN] (https://msdn.microsoft.com/en-us/library/dd783449 (v = vs.110) .aspx) формулировка «обычно называется» для каждого метода, я не могу быстро найти ссылку на строгий договор, который вы упоминаете. «последовательность завершена» обозначается «OnComplete», почему тогда существует этот специальный метод завершения, если можно использовать 'OperationCancelledException', как в TPL, когда задача отменяется маркером отмены? –

+0

@ V.B. - Взгляните на http://go.microsoft.com/fwlink/?LinkID=205219 - в частности, часть о Rx Grammar - «Сообщения, отправленные в экземпляры интерфейса IObserver, следуют следующей грамматике:« OnNext * (OnCompleted | OnError)? '. Эта грамматика позволяет наблюдаемым последовательностям отправлять любое количество (0 и более) сообщений OnNext в подписанный экземпляр наблюдателя, необязательно сопровождаемый единственным сообщением об успешном (OnCompleted) или сбое (OnError)." – Enigmativity

1

Определенно не использовать OnError для передачи данных. Как вы намекали, могут произойти плохие вещи.

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

Возможно, вы обеспокоены тем, что разворачивающий код загромождает вашу программу? Но вам не нужно писать все это в одном месте, вы можете разделить его и все еще выглядеть хорошо. Что-то вроде:

IObservable<Wrapper> source = ... 
var processed = 
    source 
    .HandleNormalCase(unwrappedNormalData => { ... }) 
    .HandleAbnormalCase(unwrappedExnData => { ... }) 

Где .HandleXxx метода расширения, которые делают развёртки.

+0

Но что, если некоторый потребитель знает только то, как обрабатывать обычные данные, который передается через 'OnNext', и должны терпеть неудачу или начало с нуля, в то время как только умные потребители знают, как обрабатывать исключительные данные? То есть плохие вещи должны произойти для неподготовленных потребителей. Вызывает беспокойство обертка: 99% -ый случай очень чувствителен к нему. –

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