It is meant to be given strings over time and output all NewLine delimited substrings. The ColumnReader is meant to be a solution for Delimiter-separated-value files, like CSV or TSV.using System;namespace fbstj{    public sealed class LineReader    {        public string NewLine { get; set; }        string _buffer = ;        public void Parse(string text)        {            _buffer += text;            var lastline = _buffer.LastIndexOf(NewLine);            if (lastline == -1)                return;            var lines = _buffer.Substring(0, lastline).Split(NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);            _buffer = _buffer.Substring(lastline);            foreach (var line in lines)                Receive(line);        }        public event Action<string> Receive = (line) => { };    }    public struct ColumnReader    {        public readonly string Delimiter;        public readonly LineReader Reader;        public ColumnReader(string newline, string delimiter) : this()        {            Reader = new LineReader { NewLine = newline };            Delimiter = delimiter;            Receive += (columns) => { };            Reader.Receive += _receive_line;        }        private void _receive_line(string line)        {            Receive(line.Split(Delimiter.ToCharArray()));        }        public event Action<string[]> Receive;    }}My main use-case is reading lines from a SerialPort:var parser = new IO.LineReader { NewLine = port.NewLine };port.DataReceived += (o, e) => parser.Parse(port.ReadExisting());parser.Receive += (line) => { };
Simple streaming parser to extract lines
c#
This looks like they used to be fields and then you made them properties:public readonly string Delimiter;public readonly LineReader Reader;IMHO that means they should get a getter and setter, like this:public string Delimiter { get; private set; }public LineReader Reader { get; private set; }String.LastIndexOf is culture-specific, so consider using a StringComparison.