CsvHelper 7 makes reading faster. To get there, the reading and writing state is used as classes: the IReadingContext and IWritingContext interfaces are removed, and everything that took or returned one uses ReadingContext or WritingContext. You're affected if your code names the interfaces: callbacks written as methods, your own exceptions, parsers or serializers, and test doubles. Code that only uses lambdas and the contexts' members compiles unchanged. The target frameworks don't change: .NET Standard 2.0 and .NET Framework 4.5.

Reading and writing contexts

Replace IReadingContext with ReadingContext, and IWritingContext with WritingContext. Lambdas need no change, since their parameter types are inferred; methods that you assign to a callback do.

Before · v6.1.1
public static class CsvCallbacks
{
    public static void OnBadData(IReadingContext context)
    {
        Console.WriteLine($"Bad data on row {context.Row}: {context.RawRecord}");
    }

    public static void OnMissingField(string[] headerNames, int index, IReadingContext context)
    {
        Console.WriteLine($"Missing field '{headerNames[0]}' on row {context.Row}.");
    }
}

using var csv = new CsvReader(reader);
csv.Configuration.BadDataFound = CsvCallbacks.OnBadData;
csv.Configuration.MissingFieldFound = CsvCallbacks.OnMissingField;
After · v7.0.0
public static class CsvCallbacks
{
    public static void OnBadData(ReadingContext context)
    {
        Console.WriteLine($"Bad data on row {context.Row}: {context.RawRecord}");
    }

    public static void OnMissingField(string[] headerNames, int index, ReadingContext context)
    {
        Console.WriteLine($"Missing field '{headerNames[0]}' on row {context.Row}.");
    }
}

using var csv = new CsvReader(reader);
csv.Configuration.BadDataFound = CsvCallbacks.OnBadData;
csv.Configuration.MissingFieldFound = CsvCallbacks.OnMissingField;
CsvHelper 6 CsvHelper 7
BadDataFound, HeaderValidated and MissingFieldFound get an IReadingContext They get a ReadingContext
Context of CsvReader, CsvParser, CsvFieldReader, IReaderRow, IParser and IFieldReader is an IReadingContext A ReadingContext
Context of CsvWriter, CsvSerializer, IWriterRow and ISerializer is an IWritingContext A WritingContext
CsvHelperException.ReadingContext and WritingContext Typed ReadingContext and WritingContext
The constructors of CsvHelperException and the exceptions derived from it take an IReadingContext or IWritingContext They take a ReadingContext or WritingContext
  • Your own exceptions: an exception derived from CsvHelperException passes a ReadingContext or WritingContext to the base constructor.
  • Your own parser or serializer: IParser.Context and ISerializer.Context return the classes, so yours returns a ReadingContext or WritingContext.
  • Test doubles: there are no interfaces to mock. Create a real context: new ReadingContext(textReader, configuration, leaveOpen) or new WritingContext(textWriter, configuration, leaveOpen).
  • ReadingContext holds fields: the reading state (Row, RawRow, Record, HeaderRecord, CurrentIndex, ColumnCount, the buffer and its positions) is in public fields instead of virtual properties, and RawRecord, Field, ParserConfiguration and ReaderConfiguration are no longer virtual. Reading them looks the same, but a class derived from ReadingContext can't override them.
  • ReadingContext.C is gone: the character the parser is on is private to the parser now.

All API changes

Every change to the public API since v6.1.1: 36 added, 46 changed, 39 removed (85 breaking). Open a type to see its changes.

CsvHelper

BadDataExceptionclass3 breaking1 removed2 changed1 added

BadDataException(ReadingContext, string)Breaking

The parameters changed from (IReadingContext, string) to (ReadingContext, string).

Before
public BadDataException(IReadingContext context, string message)
After
public BadDataException(ReadingContext context, string message)

BadDataException(ReadingContext, string, Exception)Breaking

The parameters changed from (IReadingContext, string, Exception) to (ReadingContext, string, Exception).

Before
public BadDataException(IReadingContext context, string message, Exception innerException)
After
public BadDataException(ReadingContext context, string message, Exception innerException)

Removed

BadDataException(IReadingContext)

Added

BadDataException(ReadingContext)
CsvFieldReaderclass1 breaking1 changed

ContextBreaking

The type changed from IReadingContext to ReadingContext.

Before
public virtual IReadingContext Context { get; }
After
public virtual ReadingContext Context { get; }
CsvHelperExceptionclass8 breaking2 removed6 changed2 added

CsvHelperException(ReadingContext, string)Breaking

The parameters changed from (IReadingContext, string) to (ReadingContext, string).

Before
public CsvHelperException(IReadingContext context, string message)
After
public CsvHelperException(ReadingContext context, string message)

CsvHelperException(ReadingContext, string, Exception)Breaking

The parameters changed from (IReadingContext, string, Exception) to (ReadingContext, string, Exception).

Before
public CsvHelperException(IReadingContext context, string message, Exception innerException)
After
public CsvHelperException(ReadingContext context, string message, Exception innerException)

CsvHelperException(WritingContext, string)Breaking

The parameters changed from (IWritingContext, string) to (WritingContext, string).

Before
public CsvHelperException(IWritingContext context, string message)
After
public CsvHelperException(WritingContext context, string message)

CsvHelperException(WritingContext, string, Exception)Breaking

The parameters changed from (IWritingContext, string, Exception) to (WritingContext, string, Exception).

Before
public CsvHelperException(IWritingContext context, string message, Exception innerException)
After
public CsvHelperException(WritingContext context, string message, Exception innerException)

ReadingContextBreaking

The type changed from IReadingContext to ReadingContext.

Before
public IReadingContext ReadingContext { get; }
After
public ReadingContext ReadingContext { get; }

WritingContextBreaking

The type changed from IWritingContext to WritingContext.

Before
public IWritingContext WritingContext { get; }
After
public WritingContext WritingContext { get; }

Removed

CsvHelperException(IReadingContext)CsvHelperException(IWritingContext)

Added

CsvHelperException(ReadingContext)CsvHelperException(WritingContext)
CsvParserclass1 breaking1 changed

ContextBreaking

The type changed from IReadingContext to ReadingContext.

Before
public virtual IReadingContext Context { get; }
After
public virtual ReadingContext Context { get; }
CsvReaderclass1 breaking1 changed

ContextBreaking

The type changed from IReadingContext to ReadingContext.

Before
public virtual IReadingContext Context { get; }
After
public virtual ReadingContext Context { get; }
CsvSerializerclass1 breaking1 changed

ContextBreaking

The type changed from IWritingContext to WritingContext.

Before
public virtual IWritingContext Context { get; }
After
public virtual WritingContext Context { get; }
CsvWriterclass1 breaking1 changed

ContextBreaking

The type changed from IWritingContext to WritingContext.

Before
public virtual IWritingContext Context { get; }
After
public virtual WritingContext Context { get; }
IFieldReaderinterface1 breaking1 changed

ContextBreaking

The type changed from IReadingContext to ReadingContext.

Before
IReadingContext Context { get; }
After
ReadingContext Context { get; }
IParserinterface1 breaking1 changed

ContextBreaking

The type changed from IReadingContext to ReadingContext.

Before
IReadingContext Context { get; }
After
ReadingContext Context { get; }
IReaderRowinterface1 breaking1 changed

ContextBreaking

The type changed from IReadingContext to ReadingContext.

Before
IReadingContext Context { get; }
After
ReadingContext Context { get; }
ISerializerinterface1 breaking1 changed

ContextBreaking

The type changed from IWritingContext to WritingContext.

Before
IWritingContext Context { get; }
After
WritingContext Context { get; }
IWriterRowinterface1 breaking1 changed

ContextBreaking

The type changed from IWritingContext to WritingContext.

Before
IWritingContext Context { get; }
After
WritingContext Context { get; }
MissingFieldExceptionclass3 breaking1 removed2 changed1 added

MissingFieldException(ReadingContext, string)Breaking

The parameters changed from (IReadingContext, string) to (ReadingContext, string).

Before
public MissingFieldException(IReadingContext context, string message)
After
public MissingFieldException(ReadingContext context, string message)

MissingFieldException(ReadingContext, string, Exception)Breaking

The parameters changed from (IReadingContext, string, Exception) to (ReadingContext, string, Exception).

Before
public MissingFieldException(IReadingContext context, string message, Exception innerException)
After
public MissingFieldException(ReadingContext context, string message, Exception innerException)

Removed

MissingFieldException(IReadingContext)

Added

MissingFieldException(ReadingContext)
ParserExceptionclass3 breaking1 removed2 changed1 added

ParserException(ReadingContext, string)Breaking

The parameters changed from (IReadingContext, string) to (ReadingContext, string).

Before
public ParserException(IReadingContext context, string message)
After
public ParserException(ReadingContext context, string message)

ParserException(ReadingContext, string, Exception)Breaking

The parameters changed from (IReadingContext, string, Exception) to (ReadingContext, string, Exception).

Before
public ParserException(IReadingContext context, string message, Exception innerException)
After
public ParserException(ReadingContext context, string message, Exception innerException)

Removed

ParserException(IReadingContext)

Added

ParserException(ReadingContext)
ReaderExceptionclass3 breaking1 removed2 changed1 added

ReaderException(ReadingContext, string)Breaking

The parameters changed from (IReadingContext, string) to (ReadingContext, string).

Before
public ReaderException(IReadingContext context, string message)
After
public ReaderException(ReadingContext context, string message)

ReaderException(ReadingContext, string, Exception)Breaking

The parameters changed from (IReadingContext, string, Exception) to (ReadingContext, string, Exception).

Before
public ReaderException(IReadingContext context, string message, Exception innerException)
After
public ReaderException(ReadingContext context, string message, Exception innerException)

Removed

ReaderException(IReadingContext)

Added

ReaderException(ReadingContext)
ReadingContextclass34 breaking29 removed5 changed28 added

ReadingContextBreaking

The type no longer implements IReadingContext.

Before
public class ReadingContext : IReadingContext, IDisposable
After
public class ReadingContext : IDisposable

FieldBreaking

No longer virtual: derived classes can't override it.

Before
public virtual string Field { get; }
After
public string Field { get; }

ParserConfigurationBreaking

No longer virtual: derived classes can't override it.

Before
public virtual IParserConfiguration ParserConfiguration { get; }
After
public IParserConfiguration ParserConfiguration { get; }

RawRecordBreaking

No longer virtual: derived classes can't override it.

Before
public virtual string RawRecord { get; }
After
public string RawRecord { get; }

ReaderConfigurationBreaking

No longer virtual: derived classes can't override it.

Before
public virtual IReaderConfiguration ReaderConfiguration { get; }
After
public IReaderConfiguration ReaderConfiguration { get; }

Removed

BufferBufferPositionBytePositionCCharPositionCharsReadColumnCountCreateRecordFuncsCurrentIndexFieldBuilderFieldEndPositionFieldStartPositionHasBeenReadHeaderRecordHydrateRecordActionsIsFieldBadLeaveOpenNamedIndexCacheNamedIndexesRawRecordBuilderRawRecordEndPositionRawRecordStartPositionRawRowReaderRecordRecordBuilderReusableMemberMapDataRowTypeConverterOptionsCache

Added

BufferBufferPositionBytePositionCharPositionCharsReadColumnCountCreateRecordFuncsCurrentIndexFieldBuilderFieldEndPositionFieldStartPositionHasBeenReadHeaderRecordHydrateRecordActionsIsFieldBadLeaveOpenNamedIndexCacheNamedIndexesRawRecordBuilderRawRecordEndPositionRawRecordStartPositionRawRowReaderRecordRecordBuilderReusableMemberMapDataRowTypeConverterOptionsCache
ValidationExceptionclass3 breaking1 removed2 changed1 added

ValidationException(ReadingContext, string)Breaking

The parameters changed from (IReadingContext, string) to (ReadingContext, string).

Before
public ValidationException(IReadingContext context, string message)
After
public ValidationException(ReadingContext context, string message)

ValidationException(ReadingContext, string, Exception)Breaking

The parameters changed from (IReadingContext, string, Exception) to (ReadingContext, string, Exception).

Before
public ValidationException(IReadingContext context, string message, Exception innerException)
After
public ValidationException(ReadingContext context, string message, Exception innerException)

Removed

ValidationException(IReadingContext)

Added

ValidationException(ReadingContext)
WriterExceptionclass3 breaking1 removed2 changed1 added

WriterException(WritingContext, string)Breaking

The parameters changed from (IWritingContext, string) to (WritingContext, string).

Before
public WriterException(IWritingContext context, string message)
After
public WriterException(WritingContext context, string message)

WriterException(WritingContext, string, Exception)Breaking

The parameters changed from (IWritingContext, string, Exception) to (WritingContext, string, Exception).

Before
public WriterException(IWritingContext context, string message, Exception innerException)
After
public WriterException(WritingContext context, string message, Exception innerException)

Removed

WriterException(IWritingContext)

Added

WriterException(WritingContext)
WritingContextclass1 breaking1 changed

WritingContextBreaking

The type no longer implements IWritingContext.

Before
public class WritingContext : IWritingContext, IDisposable
After
public class WritingContext : IDisposable

Removed types (2)

IReadingContextIWritingContext

CsvHelper.Configuration

Configurationclass3 breaking3 changed

BadDataFoundBreaking

The type changed from Action<IReadingContext> to Action<ReadingContext>.

Before
public virtual Action<IReadingContext> BadDataFound { get; set; }
After
public virtual Action<ReadingContext> BadDataFound { get; set; }

HeaderValidatedBreaking

The type changed from Action<bool, string[], int, IReadingContext> to Action<bool, string[], int, ReadingContext>.

Before
public virtual Action<bool, string[], int, IReadingContext> HeaderValidated { get; set; }
After
public virtual Action<bool, string[], int, ReadingContext> HeaderValidated { get; set; }

MissingFieldFoundBreaking

The type changed from Action<string[], int, IReadingContext> to Action<string[], int, ReadingContext>.

Before
public virtual Action<string[], int, IReadingContext> MissingFieldFound { get; set; }
After
public virtual Action<string[], int, ReadingContext> MissingFieldFound { get; set; }
IParserConfigurationinterface1 breaking1 changed

BadDataFoundBreaking

The type changed from Action<IReadingContext> to Action<ReadingContext>.

Before
Action<IReadingContext> BadDataFound { get; set; }
After
Action<ReadingContext> BadDataFound { get; set; }
IReaderConfigurationinterface2 breaking2 changed

HeaderValidatedBreaking

The type changed from Action<bool, string[], int, IReadingContext> to Action<bool, string[], int, ReadingContext>.

Before
Action<bool, string[], int, IReadingContext> HeaderValidated { get; set; }
After
Action<bool, string[], int, ReadingContext> HeaderValidated { get; set; }

MissingFieldFoundBreaking

The type changed from Action<string[], int, IReadingContext> to Action<string[], int, ReadingContext>.

Before
Action<string[], int, IReadingContext> MissingFieldFound { get; set; }
After
Action<string[], int, ReadingContext> MissingFieldFound { get; set; }

CsvHelper.TypeConversion

TypeConverterExceptionclass6 breaking6 changed

TypeConverterException(ITypeConverter, MemberMapData, object, WritingContext)Breaking

The parameters changed from (ITypeConverter, MemberMapData, object, IWritingContext) to (ITypeConverter, MemberMapData, object, WritingContext).

Before
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, IWritingContext context)
After
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, WritingContext context)

TypeConverterException(ITypeConverter, MemberMapData, object, WritingContext, string)Breaking

The parameters changed from (ITypeConverter, MemberMapData, object, IWritingContext, string) to (ITypeConverter, MemberMapData, object, WritingContext, string).

Before
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, IWritingContext context, string message)
After
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, WritingContext context, string message)

TypeConverterException(ITypeConverter, MemberMapData, object, WritingContext, string, Exception)Breaking

The parameters changed from (ITypeConverter, MemberMapData, object, IWritingContext, string, Exception) to (ITypeConverter, MemberMapData, object, WritingContext, string, Exception).

Before
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, IWritingContext context, string message, Exception innerException)
After
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, object value, WritingContext context, string message, Exception innerException)

TypeConverterException(ITypeConverter, MemberMapData, string, ReadingContext)Breaking

The parameters changed from (ITypeConverter, MemberMapData, string, IReadingContext) to (ITypeConverter, MemberMapData, string, ReadingContext).

Before
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, IReadingContext context)
After
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, ReadingContext context)

TypeConverterException(ITypeConverter, MemberMapData, string, ReadingContext, string)Breaking

The parameters changed from (ITypeConverter, MemberMapData, string, IReadingContext, string) to (ITypeConverter, MemberMapData, string, ReadingContext, string).

Before
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, IReadingContext context, string message)
After
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, ReadingContext context, string message)

TypeConverterException(ITypeConverter, MemberMapData, string, ReadingContext, string, Exception)Breaking

The parameters changed from (ITypeConverter, MemberMapData, string, IReadingContext, string, Exception) to (ITypeConverter, MemberMapData, string, ReadingContext, string, Exception).

Before
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, IReadingContext context, string message, Exception innerException)
After
public TypeConverterException(ITypeConverter typeConverter, MemberMapData memberMapData, string text, ReadingContext context, string message, Exception innerException)