Search code examples
c#streamgzipstreamdeflatestream

How does DeFlateStream.read redirect to System.Net.ConnectStream.Read?


In the process of debugging a code and it appears to me that DeFlateStream.read redirects to System.Net.ConnectStream.Read? When I check MSDN source code I couldn't easily find this redirection. Anyone could help me find how this occurs? thanks!


Solution

  • Streams aren't "redirected" - instead, DeflateStream.Read wraps the source stream's Read method.

    That is, the wrapping DeflateStream is passed the source Stream (i.e. in the constructor), so that when Read is called upon it, it reads the source stream (at least insofar as it can produce valid output) and then returns the processed result from it's own Read1 implementation.

    Due to Subtyping (and Inclusion Polymorphism), any object that conforms to (and is a subtype of) IO.Stream can be supplied as the source Stream. With respect to the DeflateStream code, this ensures that the wrapped _stream has a suitable Read method.

    The actual stream object supplied to the constructor might be implemented as a FileStream, a MemoryStream, a ResourceStream, a ConnectedStream, etc.

    See Polymorphism (C# Programming Guide) and Polymorphism in .NET - CodeProject (the section on Run-time Polymorphism) for additional details.


    1 From the source found here, it can be seen that it amounts to:

    public override int Read(byte[] array, int offset, int count) {
        // Setup state
    
        while(true) {
            // Process buffer into result until..
            bytesRead = inflater.Inflate(array, currentOffset, remainingCount);
            if(remainingCount == 0) {
              // ..read enough, break
            }
            if (inflater.Finished()) {
              // ..or end of source stream, break
            }
            // Making sure to read more from the source stream as required
            // (_stream is a Stream, assigned in the constructor)
            int bytes = _stream.Read( buffer, 0, buffer.Length);
            inflater.SetInput(buffer, 0 , bytes);
        }
    
        // ..
    }