我想运行一个后台任务,它从TextReader读取输入并一次处理一行.我希望阻止后台任务,直到用户将某些文本键入字段并单击提交按钮.是否有一些TextReader会在文本可用之前阻塞,并允许您以某种方式向底层源添加更多文本?
我认为指向同一个MemoryStream的StreamReader和StreamWriter可能有效,但似乎没有.StreamReader看到MemoryStream在开始时为空,并且从不再次检查.
我意识到编写ProcessLine()方法并在用户单击提交按钮时调用它会更容易.但是,我正在尝试设计一个插件架构,我希望插件看起来像带有输入流和输出流的老式控制台应用程序.我希望插件的输入流只是阻塞,直到用户点击带有一些输入文本的提交按钮.
我认为你在主应用程序中创建一个在用户点击提交时引发的事件会好得多.文本数据将在事件args中传递.每个插件都为事件注册一个事件处理程序,并处理引发事件时传入的数据.这允许许多插件处理来自单个提交的数据,而无需您进行大量的管道工作,这意味着插件可以在事件发生之前保持空闲状态.
似乎没有实现这一点 - 这很奇怪,因为我同意它将是一个有用的结构.但写起来应该很简单.这样的事情应该有效:
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); } } } }