2015-05-15 70 views
0

在Rx中有三種主要方法:OnNext<T>,OnErrorOnComplete,並且只有OnNext應該傳遞數據。使用異常作爲無效擴展中的數據傳輸對象

我有時間標記的數據點和數據流,其中有通過OnNext傳遞的正常值,佔數據點的99%以上。但是,一些數據點是例外的,例如延遲數據或無序數據點,重寫歷史記錄。從邏輯上講,下一個事件需要特殊處理的數據,而不是預期順序的下一個數據。

在這種情況下通過OnError通道傳遞例外值是否爲「正常」?我可以用T類型的屬性來定義OutOfOrderDataExcpetion<T> : Exception,並在觀察者中對其進行處理。鑑於特殊的價值是罕見的,我不拋出/增加例外,但建設和使用它們作爲DTO,性能不應該是一個問題。

我的問題是,該方法被稱爲OnError而不是OnException,但我的數據不是錯誤,它只是需要特殊處理。同時,如果我將我的observable暴露給對OutOfOrderExcpetion<T>一無所知的外部代碼,外部代碼將無法專門捕獲它,那將是一個錯誤。我可以遵循事件採購模式,並將每個數據事件封裝在一個包含命令和有效負載的包裝中,但是接下來我需要解壓每個命令,而在99%以上的情況下,它將是相同的命令「next」。使用OnError作爲所有其他命令的通道,可以讓我幾乎採用相同的事件採購模式並進行簡化處理。

除了命名問題,你能添加一些參數來阻止我使用這種設計嗎?或者這是對異常的恰當使用?

回答

2

Rx observables有一個行爲契約。您保證零或多個OnNext電話,然後是OnErrorOnCompleted的一個,並且只有一個。

如果您使用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」指示,爲什麼接下來有一個特殊的完成方法,如果在取消令牌取消任務時可以使用TPL中的OperationCancelledException? –

+0

@ V.B。 - 查看http://go.microsoft.com/fwlink/?LinkID=205219 - 特別是關於Rx語法的部分 - 「發送到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%的情況非常敏感。 –