CsvHelper 24 gives WriteConvertedField the type of the field, so that ShouldQuote gets the real type of each field when you write records, and adds a CancellationToken to the async methods that read and write records. Only code that calls or overrides WriteConvertedField, overrides those async methods, or implements IReader, IWriter or IWriterRow, has to change. The token is an optional parameter, so calls compile as they are, but a library built against 23 that calls these methods must be rebuilt. The target frameworks don't change.

WriteConvertedField

WriteConvertedField takes the type the field had before it was converted to a string, on CsvWriter and on IWriterRow. The writer passes it on to ShouldQuote as FieldType.

Before · v23.0.0
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
var total = 12.5m;
csv.WriteConvertedField(total.ToString("0.00", CultureInfo.InvariantCulture));
csv.NextRecord();
After · v24.0.0
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
var total = 12.5m;
csv.WriteConvertedField(total.ToString("0.00", CultureInfo.InvariantCulture), typeof(decimal));
csv.NextRecord();

A subclass that overrides it overrides the new signature, which the writer calls when it writes records and from WriteField<T>.

Before · v23.0.0
public class UpperCaseCsvWriter : CsvWriter
{
    public UpperCaseCsvWriter(TextWriter writer, CsvConfiguration configuration) : base(writer, configuration) { }

    public override void WriteConvertedField(string field)
    {
        base.WriteConvertedField(field?.ToUpperInvariant());
    }
}
After · v24.0.0
public class UpperCaseCsvWriter : CsvWriter
{
    public UpperCaseCsvWriter(TextWriter writer, CsvConfiguration configuration) : base(writer, configuration) { }

    public override void WriteConvertedField(string field, Type fieldType)
    {
        base.WriteConvertedField(field?.ToUpperInvariant(), fieldType);
    }
}

Cancellation

GetRecordsAsync, EnumerateRecordsAsync and WriteRecordsAsync take an optional CancellationToken. It is checked before each record, and throws an OperationCanceledException when it is canceled.

public class Order
{
    public int Id { get; set; }
}

using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
await foreach (var order in csv.GetRecordsAsync<Order>(cancellationToken))
{
    // ...
}

csv.GetRecordsAsync<Order>().WithCancellation(cancellationToken) passes the token too, and await csv.WriteRecordsAsync(orders, cancellationToken) stops writing when it is canceled. If you implement IReader or IWriter, or override these methods, add the parameter to them.

Behavior changes

  • ShouldQuote gets each member's type when you write records. In 23, WriteRecord and WriteRecords passed string as FieldType for every member of a class. In 24, it is the member's type (a member mapped with Convert still gets string), so a ShouldQuote that tests args.FieldType quotes differently.

All API changes

Every change to the public API since v23.0.0: 1 added, 14 changed (14 breaking). Open a type to see its changes.

CsvHelper

CsvReaderclass4 breaking4 changed

EnumerateRecordsAsync<T>(T, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
public virtual IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record)
After
public virtual IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record, CancellationToken cancellationToken = default)

GetRecordsAsync(Type, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
public virtual IAsyncEnumerable<object> GetRecordsAsync(Type type)
After
public virtual IAsyncEnumerable<object> GetRecordsAsync(Type type, CancellationToken cancellationToken = default)

GetRecordsAsync<T>(CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
public virtual IAsyncEnumerable<T> GetRecordsAsync<T>()
After
public virtual IAsyncEnumerable<T> GetRecordsAsync<T>(CancellationToken cancellationToken = default)

GetRecordsAsync<T>(T, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
public virtual IAsyncEnumerable<T> GetRecordsAsync<T>(T anonymousTypeDefinition)
After
public virtual IAsyncEnumerable<T> GetRecordsAsync<T>(T anonymousTypeDefinition, CancellationToken cancellationToken = default)
CsvWriterclass3 breaking3 changed

WriteConvertedField(string, Type)Breaking

The parameters changed from (string) to (string, Type).

Before
public virtual void WriteConvertedField(string field)
After
public virtual void WriteConvertedField(string field, Type fieldType)

WriteRecordsAsync(IEnumerable, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
public virtual Task WriteRecordsAsync(IEnumerable records)
After
public virtual Task WriteRecordsAsync(IEnumerable records, CancellationToken cancellationToken = default)

WriteRecordsAsync<T>(IEnumerable<T>, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
public virtual Task WriteRecordsAsync<T>(IEnumerable<T> records)
After
public virtual Task WriteRecordsAsync<T>(IEnumerable<T> records, CancellationToken cancellationToken = default)
IReaderinterface4 breaking4 changed

EnumerateRecordsAsync<T>(T, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record)
After
IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record, CancellationToken cancellationToken = default)

GetRecordsAsync(Type, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
IAsyncEnumerable<object> GetRecordsAsync(Type type)
After
IAsyncEnumerable<object> GetRecordsAsync(Type type, CancellationToken cancellationToken = default)

GetRecordsAsync<T>(CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
IAsyncEnumerable<T> GetRecordsAsync<T>()
After
IAsyncEnumerable<T> GetRecordsAsync<T>(CancellationToken cancellationToken = default)

GetRecordsAsync<T>(T, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
IAsyncEnumerable<T> GetRecordsAsync<T>(T anonymousTypeDefinition)
After
IAsyncEnumerable<T> GetRecordsAsync<T>(T anonymousTypeDefinition, CancellationToken cancellationToken = default)
IWriterinterface2 breaking2 changed

WriteRecordsAsync(IEnumerable, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
Task WriteRecordsAsync(IEnumerable records)
After
Task WriteRecordsAsync(IEnumerable records, CancellationToken cancellationToken = default)

WriteRecordsAsync<T>(IEnumerable<T>, CancellationToken)Breaking

New optional parameters (CancellationToken): calls compile unchanged, but code built against the old version must be recompiled.

Before
Task WriteRecordsAsync<T>(IEnumerable<T> records)
After
Task WriteRecordsAsync<T>(IEnumerable<T> records, CancellationToken cancellationToken = default)
IWriterRowinterface1 breaking1 changed

WriteConvertedField(string, Type)Breaking

The parameters changed from (string) to (string, Type).

Before
void WriteConvertedField(string field)
After
void WriteConvertedField(string field, Type fieldType)

CsvHelper.Configuration

MemberMapDataclass1 added

Added

Type