3

我想运行一个后台任务,从 TextReader 读取输入并一次处理一行。我希望后台任务阻止,直到用户在字段中键入一些文本并单击提交按钮。是否有一些 TextReader 会阻塞直到文本可用,并让您以某种方式向底层源添加更多文本?

我认为指向同一个 MemoryStream 的 StreamReader 和 StreamWriter 可能有效,但似乎没有。StreamReader 在开始时看到 MemoryStream 是空的,并且不再检查。

我意识到编写 ProcessLine() 方法并在用户单击提交按钮时调用它会更容易。但是,我正在尝试设计一个插件架构,我希望插件看起来像带有输入流和输出流的老式控制台应用程序。我希望插件的输入流只是阻塞,直到用户单击带有一些输入文本的提交按钮。

4

2 回答 2

6

似乎没有实现这一点 - 这很奇怪,因为我同意这将是一个有用的构造。但是写起来应该很简单。像这样的东西应该工作:

  public class BlockingStream: Stream
  {
    private readonly Stream _stream;

    public BlockingStream(Stream stream)
    {
      if(!stream.CanSeek)
        throw new ArgumentException("Stream must support seek", "stream");
      _stream = stream;
    }

    public override void Flush()
    {
      lock (_stream)
      {
        _stream.Flush();
        Monitor.Pulse(_stream);
      }
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
      lock (_stream)
      {
        long res = _stream.Seek(offset, origin);
        Monitor.Pulse(_stream);
        return res;
      }
    }

    public override void SetLength(long value)
    {
      lock (_stream)
      {
        _stream.SetLength(value);
        Monitor.Pulse(_stream);
      }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
      lock (_stream)
      {
        do
        {
          int read = _stream.Read(buffer, offset, count);
          if (read > 0)
            return read;
          Monitor.Wait(_stream);
        } while (true);
      }
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
      lock (_stream)
      {
        long currentPosition = _stream.Position;
        _stream.Position = _stream.Length;
        _stream.Write(buffer, offset, count);
        _stream.Position = currentPosition;
        Monitor.Pulse(_stream);
      }
    }

    public override bool CanRead
    {
      get
      {
        lock (_stream)
        {
          return _stream.CanRead;
        }
      }
    }

    public override bool CanSeek
    {
      get
      {
        lock (_stream)
        {
          return _stream.CanSeek;
        }
      }
    }

    public override bool CanWrite
    {
      get
      {
        lock (_stream)
        {
          return _stream.CanWrite;
        }
      }
    }

    public override long Length
    {
      get
      {
        lock (_stream)
        {
          return _stream.Length;
        }
      }
    }

    public override long Position
    {
      get
      {
        lock (_stream)
        {
          return _stream.Position;
        }
      }
      set
      {
        lock (_stream)
        {
          _stream.Position = value;
          Monitor.Pulse(_stream);
        }
      }
    }
  }
于 2008-10-29T22:48:46.347 回答
5

我认为您最好在主应用程序中创建一个在用户点击提交时引发的事件。文本数据将在事件 args 中传递。每个插件都会为事件注册一个事件处理程序,并在事件引发时处理传入的数据。这允许许多插件处理来自单个提交的数据,而无需您进行大量的管道工作,这意味着插件能够闲置直到引发事件。

于 2008-10-29T21:50:15.500 回答