如何使用不同的错误处理级联可观察量

时间:2014-12-09 13:50:34

标签: c# system.reactive reactive-programming

我有一个简单的IObservable,它从串行设备提供NMEA字符串:

     var source = Observable.Create<string>(
            observer =>
            {
                var port = new SerialPort("COM4", 4800, Parity.None, 8, StopBits.One);

                string output = string.Empty;

                port.DataReceived += (sender, eventArgs) =>
                {
                    var input = (SerialPort)sender;
                    var buffer = new byte[input.BytesToRead];

                    try
                    {
                        input.Read(buffer, 0, buffer.Length);
                    }
                    catch (Exception exception)
                    {
                        observer.OnError(exception);
                    }

                    var encoding = Encoding.ASCII;
                    var data = encoding.GetString(buffer);

                    if (data.StartsWith("$") && output != string.Empty)
                    {
                        if (output.StartsWith("$") || data.EndsWith(Environment.NewLine))
                        {
                            output = output.TrimEnd(Environment.NewLine.ToCharArray());
                            observer.OnNext(output);
                        }

                        output = data;
                    }
                    else if ((output == string.Empty || data.StartsWith("$")) || output.StartsWith("$"))
                    {
                        output += data;
                    }
                };

                try
                {
                    port.Open();
                }
                catch (Exception error)
                {
                    observer.OnError(error);
                }

                return port;
            }
        );

现在我想将这些字符串解析为稍后可以过滤的具体消息类型。 因此,IObservable需要更专业化为IObservable。

这可以通过.Select()语句解决,其中结果被重新投影到NMEAMessage中...... (以下只是简单重投影的一个例子)

var selected = source.Select(s => { return new NmeaMessage(s); });

...但是如果无法进行重投影会发生什么(例如,传递的字符串的未知消息类型或解析错误)。怎么处理?我不能在这里调用OnError(因为它是一个Observable而不是Observer。只是抑制解析错误并且在这种情况下不返回任何内容?如何声明源可能不是有效的NMEA源?我应该创建一个虚拟的“Device” “class(使用里面的字符串源代码)而不是级联或过滤Observables?”Device“类可以使用事件,然后可以再次创建一个Observable(Observable.FromEventPattern&lt;&gt;)。

我还希望“观察”Parser能够订阅不同的IObservable源。将解析器和重新投影集成到此场景中的最佳方法是什么?

1 个答案:

答案 0 :(得分:3)

NmeaMessage构造函数包装在这样的静态函数中:

public static NmeaMessage TryParseNmeaMessage(TInputData d)
{
    if (IsValidInput(d))
        return new NmeaMessage(d);
    else
        return null;
}

然后你可以这样做:

var inputData = Observable.Create(...);
var parsed    = inputData.Select(d => TryParseNmeaMessage(d))
                         .Where(d => d != null);

显然你也需要定义IsValidInput()

而不是null,你也可以从ParseMessage返回一些BadNmeaMessage(包含错误信息的NmeaMessage的子类)。
然后,您可以使用.OfType<(Bad)NmeaMessage>()分别对好/坏消息做出反应。

或者您可以发出OnError信号(在ParseMessage中抛出),然后重新启动序列。

有关高级错误处理的信息,请参阅here

在F#中有一篇关于此类错误处理的优秀文章:Railway oriented programming 相同的原则可以在带有RX的C#中使用。