Обработка исключений в реактивных расширениях без остановки последовательности

Почему RX имеет следующую грамматику OnNext* (OnError|OnCompleted)? вместо (OnNext|OnError)* OnCompleted? Это довольно ясно с точки зрения реализации (также это имеет общую семантику с IEnumerable а также yield) но я думаю, что отличается от реальной жизни. В реальной жизни - производители генерируют смешанный поток данных и исключений (и исключения не нарушают производителя).

Вопрос: если я правильно понял, единственно возможное решение - сделать наблюдаемую возвращаемую сложную структуру данных объединенной из исходных данных и произведенных исключений (Observable.Timestamp() а также .TimeInterval() имеет похожую концепцию) или есть другие варианты?


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

public class ValueOrException<T>
{
    private readonly Exception ex;
    private readonly T value;

    public ValueOrException(T value, Exception ex)
    {
        this.value = value;
        this.ex = ex;
    }

    public ValueOrException(T value)
    {
        this.value = value;
    }

    public T Value
    {
        get { return this.value; }
    }

    public Exception Ex
    {
        get { return this.ex; }
    }
}

3 ответа

Решение

Если потребитель тот, кто знает, является ли Exception ожидается или нет, тогда я говорю, что выбрасывать исключения здесь неправильно.

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

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

Tuple<T, Exception> будет работать в крайнем случае, но отсутствие специфичности вокруг типа (а также свойств), как правило, беспорядочно, поэтому я бы рекомендовал создать выделенный тип для передачи результатов вашей работы и раскрывается через IObservable<T>,

OnError - это сообщение о том, что произошла неисправимая ошибка, поэтому поток должен быть сброшен. После восстановления следующие события не имеют смысла в контексте событий, произошедших до исключения.

Например, рассмотрим поток событий:

  • Пользователь присоединился к чату
  • Пользователь присоединился к чату
  • !! Сбой чата, так что всех пользователей выгнали
  • Пользователь присоединился к чату

Теперь потребитель потока использует функцию Aggregate для отображения количества чатов. Что должно отображаться в конце? Конечно, 1, а не 3. Мы должны начать считать с нуля после исключения.

ValueOrException выглядит как Либо тип из функционального программирования. Вы только что поменялись местами влево и вправо. По соглашению, Right используется для успеха, а Left - для неудачи.

Другие вопросы по тегам