16

このインターフェイスを実装するオブジェクトを提供する必要があるライブラリを使用しています。

public interface IConsole {
    TextWriter StandardInput { get; }
    TextReader StandardOutput { get; }
    TextReader StandardError { get; }
}

次に、オブジェクトのリーダーは、ライブラリによって次のように使用されます。

IConsole console = new MyConsole();
int readBytes = console.StandardOutput.Read(buffer, 0, buffer.Length);

通常、IConsoleを実装するクラスには、外部プロセスからのStandardOutputストリームがあります。その場合、console.StandardOutput.Read呼び出しは、StandardOutputストリームに書き込まれるデータが得られるまでブロックすることで機能します。

私がやろうとしているのは、MemoryStreamsを使用するテストIConsole実装を作成し、StandardInputに表示されるものをStandardInputにエコーバックすることです。私は試した:

MemoryStream echoOutStream = new MemoryStream();
StandardOutput = new StreamReader(echoOutStream);

しかし、それに関する問題は、いくつかのデータが得られるまで、console.StandardOutput.Readがブロックではなく0を返すことです。とにかく、利用可能なデータがない場合にMemoryStreamをブロックすることができますか、または使用できるメモリストリームに別のものがありますか?

4

5 に答える 5

13

あなたの答えに触発されて、これが私のマルチスレッド、マルチ書き込みバージョンです:

public class EchoStream : MemoryStream
{
    private readonly ManualResetEvent _DataReady = new ManualResetEvent(false);
    private readonly ConcurrentQueue<byte[]> _Buffers = new ConcurrentQueue<byte[]>();

    public bool DataAvailable{get { return !_Buffers.IsEmpty; }}

    public override void Write(byte[] buffer, int offset, int count)
    {
        _Buffers.Enqueue(buffer);
        _DataReady.Set();
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        _DataReady.WaitOne();

        byte[] lBuffer;

        if (!_Buffers.TryDequeue(out lBuffer))
        {
            _DataReady.Reset();
            return -1;
        }

        if (!DataAvailable)
            _DataReady.Reset();

        Array.Copy(lBuffer, buffer, lBuffer.Length);
        return lBuffer.Length;
    }
}

お使いのバージョンでは、連続して書き込みを行うことなく、書き込み時にストリームを読み取る必要があります。私のバージョンでは、書き込まれたバッファーを ConcurrentQueue にバッファーします (単純な Queue に変更してロックするのはかなり簡単です)。

于 2013-10-02T12:54:28.713 に答える
10

結局、MemoryStreamから継承し、ReadメソッドとWriteメソッドを引き継ぐことで、それを行う簡単な方法を見つけました。

public class EchoStream : MemoryStream {

    private ManualResetEvent m_dataReady = new ManualResetEvent(false);
    private byte[] m_buffer;
    private int m_offset;
    private int m_count;

    public override void Write(byte[] buffer, int offset, int count) {
        m_buffer = buffer;
        m_offset = offset;
        m_count = count;
        m_dataReady.Set();
    }

    public override int Read(byte[] buffer, int offset, int count) {
        if (m_buffer == null) {
            // Block until the stream has some more data.
            m_dataReady.Reset();
            m_dataReady.WaitOne();    
        }

        Buffer.BlockCopy(m_buffer, m_offset, buffer, offset, (count < m_count) ? count : m_count);
        m_buffer = null;
        return (count < m_count) ? count : m_count;
    }
}
于 2009-09-28T00:52:47.287 に答える