public IEnumerable <TModel> Read() { _errors.Clear(); var rowIndex = 0; var firstRow = RowReader.Read(); if (firstRow == null) { if (HasHeader) { throw new TableIOException(new[] { new ErrorDetail { Type = "NoTableHeader", Message = "Table header is none." } }); } else { yield break; } } // decide valid column size. // ** all row's column size must be valid column size. ** var validColumnSize = ColumnSize ?? firstRow.Count; if (PropertyMapper.RequiredHeaderOnRead && !HasHeader) { throw new TableIOException(new[] { new ErrorDetail { Type = "HeaderRequired", Message = $"Header is required on read.", RowIndex = rowIndex } }); } var propertyMaps = PropertyMapper.CreatePropertyMaps(typeof(TModel), HasHeader ? firstRow.Select(f => $"{f}").ToArray() : null); var propertyMapMaxColumnIndex = propertyMaps.Any() ? propertyMaps.Max(m => m.ColumnIndex) : -1; if (propertyMapMaxColumnIndex >= validColumnSize) { throw new TableIOException(new[] { new ErrorDetail { Type = "OutOfRangeColumnIndexMapping", Message = $"Max column index({propertyMapMaxColumnIndex}) of property mapping is greater than or equal to valid column size({validColumnSize}).", RowIndex = rowIndex } }); } var row = firstRow; if (HasHeader) { rowIndex++; row = RowReader.Read(); } while (row != null) { if (row.Count != validColumnSize) { _errors.Add(new ErrorDetail { Type = "InvalidColumnSize", Message = "Column size is invalid.", RowIndex = rowIndex }); if (_errors.Count >= ErrorLimit) { throw new TableIOException(_errors); } } else { yield return(ConvertFromRow(row, rowIndex, propertyMaps)); } rowIndex++; row = RowReader.Read(); } if (_errors.Any()) { throw new TableIOException(_errors); } }