Assuming you want your custom StreamReader to be used wherever TextReader can be used, there are usually two options.
Inherit from StreamReader and redefine functions that you want to work differently. In your case, it will be StreamReader.ReadLine.
Inherit from TextReader and fully realize the readerโs capabilities according to your requirements.
Note. For option 2 above, you can save the internal reference to the StreamReader instance and delegate all functions to the internal instance, except for the part of the functionality that you want to replace. In my opinion, this is just a detail of the implementation of option 2, and not the third option.
Based on your question, I assume that you tried option 1 and found that redefining StreamReader.ReadLine is quite difficult because you cannot access the internal functions of the class. Well, for StreamReader you are lucky and can achieve this without having access to the internal StreamReader implementation.
Here is a simple example:
Disclaimer: ReadLine() implementation is intended for demonstration purposes and is not intended for reliable or complete implementation.
class CustomStreamReader : StreamReader { public CustomStreamReader(Stream stream) : base(stream) { } public override string ReadLine() { int c; c = Read(); if (c == -1) { return null; } StringBuilder sb = new StringBuilder(); do { char ch = (char)c; if (ch == ',') { return sb.ToString(); } else { sb.Append(ch); } } while ((c = Read()) != -1); return sb.ToString(); } }
You will notice that I just used the StreamReader.Read () method to read the characters from the stream. Although it is definitely less for the formant that works directly with internal buffers, the Read() method uses internal buffering, so it should bring pretty good performance, but it should be checked for confirmation.
For fun, here is an example of option 2. I used the encapsulated StreamReader to reduce the actual code, this is not verified at all.
class EncapsulatedReader : TextReader { private StreamReader _reader; public EncapsulatedReader(Stream stream) { _reader = new StreamReader(stream); } public Stream BaseStream { get { return _reader.BaseStream; } } public override string ReadLine() { int c; c = Read(); if (c == -1) { return null; } StringBuilder sb = new StringBuilder(); do { char ch = (char)c; if (ch == ',') { return sb.ToString(); } else { sb.Append(ch); } } while ((c = Read()) != -1); return sb.ToString(); } protected override void Dispose(bool disposing) { if (disposing) { _reader.Close(); } base.Dispose(disposing); } public override int Peek() { return _reader.Peek(); } public override int Read() { return _reader.Read(); } public override int Read(char[] buffer, int index, int count) { return _reader.Read(buffer, index, count); } public override int ReadBlock(char[] buffer, int index, int count) { return _reader.ReadBlock(buffer, index, count); } public override string ReadToEnd() { return _reader.ReadToEnd(); } public override void Close() { _reader.Close(); base.Close(); } }