C#5 ReadAsync和迭代器

时间:2012-10-31 13:21:53

标签: c# iterator system.reactive async-await c#-5.0

我正在尝试将下面的类转换为lazily返回一个文件。

public class ObservableFile2 : IObservable<string>
{
    private readonly IObservable<string> subject;

    public ObservableFile2(string fileName)
    {
        subject = Observable.Using<string, StreamReader>
            (
                () => new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)),
                streamReader => ObserveLines(streamReader)
            );
    }

    private IObservable<string> ObserveLines(StreamReader streamReader)
    {
        return ReadLines(streamReader).ToObservable();
    }

    private IEnumerable<string> ReadLines(StreamReader streamReader)
    {
        while (!streamReader.EndOfStream)
        {
            yield return streamReader.ReadLine();
        }
    }        

    public IDisposable Subscribe(IObserver<string> observer)
    {
        return subject.Subscribe(observer);
    }
}

我现在正尝试将其转换为使用

StreamReader.ReadLineAsync() 

甚至更好的是将数据分块,即

await SourceStream.ReadAsync(buffer, 0, chunkSize). 

我似乎没有掌握如何 包装和解包任务

欢迎提供援助。

由于

2 个答案:

答案 0 :(得分:8)

不是 Rx主人,所以可能有比我的回答更好的方法。

我认为应该可以使用async启用Create

public static class ObservableFile2
{
  public static IObservable<string> Create(string fileName)
  {
    return Observable.Create<string>(async (subject, token) =>
    {
      try
      {
        using (var streamReader = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
          while (true)
          {
            token.ThrowIfCancellationRequested();
            var line = await streamReader.ReadLineAsync();
            if (line == null)
            {
              subject.OnCompleted();
              return;
            }
            subject.OnNext(line);
          }
        }
      }
      catch (Exception ex)
      {
        subject.OnError(ex);
      }
    });
  }
}

答案 1 :(得分:0)

我不知道您的解决方案是否需要async-features,因为您没有提及它 - 我只能看到您想要“懒洋洋地”使用该文件 - 我的猜测是您希望获得一次一行,如果是这样,这个应该做的伎俩:

public static IEnumerable<string> EnumerateLines(string fileName)
{
    using (
        var streamReader =
            new StreamReader(new FileStream(fileName,
                                            FileMode.Open,
                                            FileAccess.Read,
                                            FileShare.Read)))
    {
        while (true)
        {
            if (streamReader.EndOfStream)
                yield break;

            Console.WriteLine("read another line...");
            yield return streamReader.ReadLine();
        }
    }
}

请注意,这仅取决于StreamReader.ReadLine的实现细节。 您可以尝试通过使用Lazy来进行非严格评估 - 但是然后您会因为丢失文件句柄而遇到麻烦,因为您不知道值何时被消耗掉(即使Haskell有这个问题:)) - 我的建议:不要尝试使用文件 lazy ...这可以让你轻松陷入困境