Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 生成IObservable的首选方法<;字符串>;溪流_C#_System.reactive_Reactive Programming - Fatal编程技术网

C# 生成IObservable的首选方法<;字符串>;溪流

C# 生成IObservable的首选方法<;字符串>;溪流,c#,system.reactive,reactive-programming,C#,System.reactive,Reactive Programming,作为我们应用程序的一部分(目前已投入生产大约4个月),我们有一个来自外部设备的数据流,我们将其转换为IObservable 到目前为止,我们一直在使用下面的代码来生成它,并且它运行得非常好 IObservable<string> ObserveStringStream(Stream inputStream) { var streamReader = new StreamReader(inputStream); return Observable

作为我们应用程序的一部分(目前已投入生产大约4个月),我们有一个来自外部设备的数据流,我们将其转换为IObservable

到目前为止,我们一直在使用下面的代码来生成它,并且它运行得非常好

IObservable<string> ObserveStringStream(Stream inputStream)
{
    var streamReader = new StreamReader(inputStream);
    return Observable
            .Create<string>(observer => Scheduler.ThreadPool
            .Schedule(() => ReadLoop(streamReader, observer)));
}

private void ReadLoop(StreamReader reader, IObserver<string> observer)
{
    while (true)
    {
        try
        {
            var line = reader.ReadLine();
            if (line != null)
            {
                observer.OnNext(line);
            }
            else
            {
                observer.OnCompleted();
                break;
            }
        }
        catch (Exception ex)
        {
            observer.OnError(ex);
            break;
        }
    }
}

它似乎工作得很好,而且更干净,但我想知道一种方法是否优于另一种方法,或者是否有更好的方法。

我认为你有一个好主意(将
转换为
可枚举
然后
可观察
)。但是,IEnumerable代码可以更干净:

IEnumerable<string> ReadLines(Stream stream)
{
    using (StreamReader reader = new StreamReader(stream))
    {
        while (!reader.EndOfStream)
            yield return reader.ReadLine();
    }
}
IEnumerable可读行(流)
{
使用(StreamReader=新StreamReader(stream))
{
而(!reader.EndOfStream)
产生返回reader.ReadLine();
}
}
然后对于可观察的IObservable

IObservable<string> ObserveLines(Stream inputStream)
{
    return ReadLines(inputStream).ToObservable(Scheduler.ThreadPool);
}
IObservable observeline(流输入流)
{
返回ReadLines(inputStream).ToObservable(Scheduler.ThreadPool);
}
这是更短、更可读的,并且正确地处理了流。它也很懒


ToObservable
扩展负责捕获
OnNext
事件(新行)以及
OnCompleted
事件(可枚举的结尾)和
OnError
我手头没有代码,但这里介绍了如何执行异步预异步CTP

[略读读者注意:如果您不需要进行太多扩展,则无需费心]

创建一个本身可观察的AsyncTextReader实现。ctor接收一个流,并对该流执行起始(256bytes),将自身作为延续传递,然后返回

输入continuation后,调用EndRead,并将返回的字节添加到类的一个小缓冲区中。重复此操作,直到缓冲区包含一个或多个行尾序列(根据TextWriter)。发生这种情况时,通过Observable接口将缓冲区的这些位作为字符串发送出去,然后重复

完成后,发出完成信号等。。。(并处理该流)。如果在continuation中从EndReadByte引发异常,请捕获它并将其传递给OneError接口

调用代码如下所示:

IObservable=新的AsyncTextReader(流)

这个比例很好。只需要确保在处理缓冲区时不要做太愚蠢的事情

伪代码:

public ctor(Stream stream){
    this._stream = stream;
    BeginRead();
    return;
}

private void BeginRead(){
    // kick of async read and return (synchronously)
    this._stream.BeginRead(_buffer,0,256,EndRead,this);
}

private void EndRead(IAsyncResult result){
    try{
        // bytesRead will be *up to* 256
        var bytesRead = this._stream.EndRead(result);
        if(bytesRead < 1){
            OnCompleted();
            return;
        }
        // do work with _buffer, _listOfBuffers
        // to get lines out etc...
        OnNext(aLineIFound); // times n
        BeginRead(); // go round again
    }catch(Exception err){
        OnException(err);
    }
}
public-ctor(流){
这个。_stream=stream;
开始();
返回;
}
私有的无效开始(){
//异步读取和返回的触发(同步)
this._stream.BeginRead(_buffer,0256,EndRead,this);
}
私有void EndRead(IAsyncResult结果){
试一试{
//字节读取将为*至*256
var bytesRead=this.\u stream.EndRead(结果);
如果(字节读取<1){
未完成();
返回;
}
//请使用_buffer、_buffers列表
//把线路排出去等等。。。
OnNext(aLineIFound);//次n
beginhead();//再绕一圈
}捕获(异常错误){
一个例外(err);
}
}
好的,这是APM,只有母亲才会喜欢。我热切地等待着另一种选择


ps:读者是否应该关闭流是一个有趣的问题。我说不,因为它没有创建它。

使用async/await支持,以下最有可能是您的最佳选择:

IObservable<string> ObserveStringStream(Stream inputStream)
{
    return Observable.Using(() => new StreamReader(inputStream), 
        sr => Observable.Create<string>(async (obs, ct) =>
        {
            while (true)
            {
                ct.ThrowIfCancellationRequested();
                var line = await sr.ReadLineAsync().ConfigureAwait(false);
                if (line == null)
                    break;
                obs.OnNext(line);
            }
            obs.OnCompleted();
    }));
}
IObservable ObserveStringStream(流输入流)
{
返回可观察的。使用(()=>新的StreamReader(inputStream),
sr=>Observable.Create(异步(obs,ct)=>
{
while(true)
{
ct.ThrowIfCancellationRequested();
var line=await sr.ReadLineAsync().ConfigureAwait(false);
如果(行==null)
打破
obs.OnNext(行);
}
obs.OnCompleted();
}));
}

Pro:
yield return
支持延迟/延迟加载集合。Con:当抛出异常时,它不会调用一个异常,它只是冒泡,我想这取决于您是否介意烧掉一个线程来执行读取循环,这取决于您需要支持的设备数量。我写了一个AsyncTextReader,它本身可以观察到做一些类似的事情,但规模很大。当然这些天你可以等待一些事情…@MatthewFinlay事实上,一个例外似乎是有效的,如果我订阅并包括OnNext、OnError和OnCompleted的操作,我会得到所有3个被称为预期的Hanks Lee。我确实读过那篇文章。它是可观察的吗?使用它可以支持取消?如果是这样的话,这样的东西不能工作(基于我的ReadLoop方法)?可观察。使用(()=>newstreamreader(inputStream),sr=>ReadLoop(sr).ToObservable(Scheduler.ThreadPool));很好,很干净。明天我得试一试。我唯一担心的是,我可能会得到一个尾随null作为可观察项中的最后一项,但这很容易过滤掉。其中(line=>line!=null)
IObservable<string> ObserveStringStream(Stream inputStream)
{
    return Observable.Using(() => new StreamReader(inputStream), 
        sr => Observable.Create<string>(async (obs, ct) =>
        {
            while (true)
            {
                ct.ThrowIfCancellationRequested();
                var line = await sr.ReadLineAsync().ConfigureAwait(false);
                if (line == null)
                    break;
                obs.OnNext(line);
            }
            obs.OnCompleted();
    }));
}