Monday, 17 September 2018

Understanding Streams (in .NET) #2

In Part 1 we looked at streams from a conceptual point of view. We learnt that streams are an abstraction over moving data from point A to point B. A very simple example of reading from a stream can be used to demonstrate this:

The GetStream() method returns a stream object from which we can read bytes until we are told there are no more bytes to read, which is indicated by -1 being returned. The stream abstraction is already working for us here as we've no idea - and potentially don't care - about where the data is coming from: we can simply keep asking for data until we're told there's no more data to be had.

To peek behind the curtain a little here is the GetStream() method:

All I'm doing here is converting a string into an byte array where each byte is the ASCII representation of a character in the string. I then create a new MemoryStream object passing the byte array in to the constructor. Through the power of inheritance and the Liskov substitution principle we can treat the MemoryStream as it's parent Stream object.
On its own this doesn't seem terribly useful. But the data in the Stream doesn't have to be from an in-memory source. I could change the GetStream() method to the following and still read from it in the same way, even though the data now exists in a file:

I could even be reading from a stream whose bytes come over the internet:

These examples are a little contrived and not awfully useful as all I do with the byte I've read is write it out to the console and move onto the next one. That being said, bytes are the essential nature of all data, so we have an solid starting point to do more interesting things...

No comments:

Post a Comment