Migration guide
Migrating to v23.0.0
Moving to v23.0.0 from v22.1.2. Changelog.
CsvHelper 23 changes every callback to take one argument: a struct with a property for each value the callback used
to get as a parameter. New values can then be added without breaking your code, and BadDataFound already gets one,
the bad field. The properties of CsvConfiguration have setters again (they were init from 20 to 22) so that
Visual Basic can set them, and the constructor that took every setting as an optional argument is removed. The target
frameworks don't change.
Configuration
The constructor with every setting as an optional argument, added in 21.0.5 for Visual Basic, is removed. The properties have setters now, so set them in an object initializer, or one at a time.
var config = new CsvConfiguration(CultureInfo.InvariantCulture, delimiter: ";", hasHeaderRecord: false);var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = ";",
HasHeaderRecord = false,
};Code that sets the properties in an object initializer doesn't change. Set them before you create the reader or writer: the reader, the parser and the writer copy most settings when they are created.
Callbacks
Each callback gets an args struct named after it (BadDataFoundArgs, PrepareHeaderForMatchArgs and so on), with
a property for each former parameter.
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
PrepareHeaderForMatch = (header, fieldIndex) => header.ToLower(),
ShouldSkipRecord = record => record.All(string.IsNullOrWhiteSpace),
MissingFieldFound = (headerNames, index, context) => Console.WriteLine($"Missing field {index}"),
BadDataFound = context => Console.WriteLine($"Bad data: {context.Parser.RawRecord}"),
ReadingExceptionOccurred = exception =>
{
Console.WriteLine(exception.Message);
return false;
},
GetDynamicPropertyName = (context, fieldIndex) => $"Field{fieldIndex}",
};var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
PrepareHeaderForMatch = args => args.Header.ToLower(),
ShouldSkipRecord = args => args.Record.All(string.IsNullOrWhiteSpace),
MissingFieldFound = args => Console.WriteLine($"Missing field {args.Index}"),
BadDataFound = args => Console.WriteLine($"Bad data: {args.Context.Parser.RawRecord}"),
ReadingExceptionOccurred = args =>
{
Console.WriteLine(args.Exception.Message);
return false;
},
GetDynamicPropertyName = args => $"Field{args.FieldIndex}",
};| Callback | CsvHelper 22 parameters | CsvHelper 23 args properties |
|---|---|---|
BadDataFound |
context |
Field (new: the bad field), Context |
GetConstructor |
classType |
ClassType |
GetDynamicPropertyName |
context, fieldIndex |
Context, FieldIndex |
HeaderValidated |
invalidHeaders, context |
InvalidHeaders, Context |
MissingFieldFound |
headerNames, index, context |
HeaderNames, Index, Context |
PrepareHeaderForMatch |
header, fieldIndex |
Header, FieldIndex |
ReadingExceptionOccurred |
exception |
Exception |
ReferenceHeaderPrefix |
memberType, memberName |
MemberType, MemberName |
ShouldQuote |
field, fieldType, row |
Field, FieldType, Row |
ShouldSkipRecord |
record |
Record |
ShouldUseConstructorParameters |
parameterType |
ParameterType |
Convert when reading |
row |
Row (ConvertFromStringArgs) |
Convert when writing |
value |
Value (ConvertToStringArgs<TClass>) |
Validate |
field |
Field |
Setting a callback to null, such as MissingFieldFound = null, doesn't change.
Mapping
Convert and Validate on a member map take the args too.
public class Order
{
public int Id { get; set; }
public decimal Total { get; set; }
}
public sealed class OrderMap : ClassMap<Order>
{
public OrderMap()
{
Map(m => m.Id).Validate(field => !string.IsNullOrEmpty(field));
Map(m => m.Total)
.Convert(row => row.GetField<decimal>("Net") + row.GetField<decimal>("Tax"))
.Convert(order => order.Total.ToString("0.00"));
}
}public class Order
{
public int Id { get; set; }
public decimal Total { get; set; }
}
public sealed class OrderMap : ClassMap<Order>
{
public OrderMap()
{
Map(m => m.Id).Validate(args => !string.IsNullOrEmpty(args.Field));
Map(m => m.Total)
.Convert(args => args.Row.GetField<decimal>("Net") + args.Row.GetField<decimal>("Tax"))
.Convert(args => args.Value.Total.ToString("0.00"));
}
}Calling a callback
The default functions in ConfigurationFunctions take the args too, so a callback that calls the default passes its
args on.
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
// Quote what CsvHelper quotes, and numbers with leading zeros.
ShouldQuote = (field, fieldType, row) => ConfigurationFunctions.ShouldQuote(field, fieldType, row) || (field != null && field.StartsWith("0")),
};var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
// Quote what CsvHelper quotes, and numbers with leading zeros.
ShouldQuote = args => ConfigurationFunctions.ShouldQuote(args) || (args.Field != null && args.Field.StartsWith("0")),
};To call a callback yourself, in a test for example, create its args with their constructor.
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
PrepareHeaderForMatch = (header, fieldIndex) => header.Trim().ToLower(),
};
var name = config.PrepareHeaderForMatch(" Name ", 0);var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
PrepareHeaderForMatch = args => args.Header.Trim().ToLower(),
};
var name = config.PrepareHeaderForMatch(new PrepareHeaderForMatchArgs(" Name ", 0));Behavior changes
Flushflushes theTextWriter.CsvWriter.Flush()andFlushAsync()write the writer's buffer to theTextWriterand then flush theTextWritertoo.NextRecord()andNextRecordAsync()write the buffer to theTextWriterwithout flushing it, as before, but no longer callFlush()andFlushAsync(): if your subclass overrides them to run after each record, override the new protectedFlushBuffer()andFlushBufferAsync()instead. A subclass can also write text to the buffer with the new protectedWriteToBuffer(string).
All API changes
Every change to the public API since v22.1.2: 17 added, 63 changed, 1 removed (50 breaking). Open a type to see its changes.
CsvHelper
BadDataFounddelegate1 changed
BadDataFound
The declaration changed.
public delegate void BadDataFound(CsvContext context)public delegate void BadDataFound(BadDataFoundArgs args)ConvertFromString<TMember>delegate1 changed
ConvertFromString<TMember>
The declaration changed.
public delegate TMember ConvertFromString<TMember>(IReaderRow row)public delegate TMember ConvertFromString<TMember>(ConvertFromStringArgs args)ConvertToString<TClass>delegate1 changed
ConvertToString<TClass>
The declaration changed.
public delegate string ConvertToString<TClass>(TClass value)public delegate string ConvertToString<TClass>(ConvertToStringArgs<TClass> args)CsvContextclass2 breaking2 changed
TypeConverterCacheBreaking
The init accessor was removed.
public virtual TypeConverterCache TypeConverterCache { get; init; }public virtual TypeConverterCache TypeConverterCache { get; set; }TypeConverterOptionsCacheBreaking
The init accessor was removed.
public virtual TypeConverterOptionsCache TypeConverterOptionsCache { get; init; }public virtual TypeConverterOptionsCache TypeConverterOptionsCache { get; set; }CsvWriterclass3 added
Added
GetConstructordelegate1 changed
GetConstructor
The declaration changed.
public delegate ConstructorInfo GetConstructor(Type classType)public delegate ConstructorInfo GetConstructor(GetConstructorArgs args)GetDynamicPropertyNamedelegate1 changed
GetDynamicPropertyName
The declaration changed.
public delegate string GetDynamicPropertyName(CsvContext context, int fieldIndex)public delegate string GetDynamicPropertyName(GetDynamicPropertyNameArgs args)HeaderValidateddelegate1 changed
HeaderValidated
The declaration changed.
public delegate void HeaderValidated(InvalidHeader[] invalidHeaders, CsvContext context)public delegate void HeaderValidated(HeaderValidatedArgs args)MissingFieldFounddelegate1 changed
MissingFieldFound
The declaration changed.
public delegate void MissingFieldFound(string[] headerNames, int index, CsvContext context)public delegate void MissingFieldFound(MissingFieldFoundArgs args)PrepareHeaderForMatchdelegate1 changed
PrepareHeaderForMatch
The declaration changed.
public delegate string PrepareHeaderForMatch(string header, int fieldIndex)public delegate string PrepareHeaderForMatch(PrepareHeaderForMatchArgs args)ReadingExceptionOccurreddelegate1 changed
ReadingExceptionOccurred
The declaration changed.
public delegate bool ReadingExceptionOccurred(CsvHelperException exception)public delegate bool ReadingExceptionOccurred(ReadingExceptionOccurredArgs args)ReferenceHeaderPrefixdelegate1 changed
ReferenceHeaderPrefix
The declaration changed.
public delegate string ReferenceHeaderPrefix(Type memberType, string memberName)public delegate string ReferenceHeaderPrefix(ReferenceHeaderPrefixArgs args)ShouldQuotedelegate1 changed
ShouldQuote
The declaration changed.
public delegate bool ShouldQuote(string field, Type fieldType, IWriterRow row)public delegate bool ShouldQuote(ShouldQuoteArgs args)ShouldSkipRecorddelegate1 changed
ShouldSkipRecord
The declaration changed.
public delegate bool ShouldSkipRecord(string[] record)public delegate bool ShouldSkipRecord(ShouldSkipRecordArgs args)ShouldUseConstructorParametersdelegate1 changed
ShouldUseConstructorParameters
The declaration changed.
public delegate bool ShouldUseConstructorParameters(Type parameterType)public delegate bool ShouldUseConstructorParameters(ShouldUseConstructorParametersArgs args)Validatedelegate1 changed
Validate
The declaration changed.
public delegate bool Validate(string field)public delegate bool Validate(ValidateArgs args)Added types (14)
CsvHelper.Configuration
ConfigurationFunctionsstatic class10 breaking10 changed
BadDataFound(BadDataFoundArgs)Breaking
The parameters changed from (CsvContext) to (BadDataFoundArgs).
public static void BadDataFound(CsvContext context)public static void BadDataFound(BadDataFoundArgs args)GetConstructor(GetConstructorArgs)Breaking
The parameters changed from (Type) to (GetConstructorArgs).
public static ConstructorInfo GetConstructor(Type type)public static ConstructorInfo GetConstructor(GetConstructorArgs args)GetDynamicPropertyName(GetDynamicPropertyNameArgs)Breaking
The parameters changed from (CsvContext, int) to (GetDynamicPropertyNameArgs).
public static string GetDynamicPropertyName(CsvContext context, int fieldIndex)public static string GetDynamicPropertyName(GetDynamicPropertyNameArgs args)HeaderValidated(HeaderValidatedArgs)Breaking
The parameters changed from (InvalidHeader[], CsvContext) to (HeaderValidatedArgs).
public static void HeaderValidated(InvalidHeader[] invalidHeaders, CsvContext context)public static void HeaderValidated(HeaderValidatedArgs args)MissingFieldFound(MissingFieldFoundArgs)Breaking
The parameters changed from (string[], int, CsvContext) to (MissingFieldFoundArgs).
public static void MissingFieldFound(string[] headerNames, int index, CsvContext context)public static void MissingFieldFound(MissingFieldFoundArgs args)PrepareHeaderForMatch(PrepareHeaderForMatchArgs)Breaking
The parameters changed from (string, int) to (PrepareHeaderForMatchArgs).
public static string PrepareHeaderForMatch(string header, int index)public static string PrepareHeaderForMatch(PrepareHeaderForMatchArgs args)ReadingExceptionOccurred(ReadingExceptionOccurredArgs)Breaking
The parameters changed from (CsvHelperException) to (ReadingExceptionOccurredArgs).
public static bool ReadingExceptionOccurred(CsvHelperException exception)public static bool ReadingExceptionOccurred(ReadingExceptionOccurredArgs args)ShouldQuote(ShouldQuoteArgs)Breaking
The parameters changed from (string, Type, IWriterRow) to (ShouldQuoteArgs).
public static bool ShouldQuote(string field, Type fieldType, IWriterRow row)public static bool ShouldQuote(ShouldQuoteArgs args)ShouldSkipRecord(ShouldSkipRecordArgs)Breaking
The parameters changed from (string[]) to (ShouldSkipRecordArgs).
public static bool ShouldSkipRecord(string[] record)public static bool ShouldSkipRecord(ShouldSkipRecordArgs args)ShouldUseConstructorParameters(ShouldUseConstructorParametersArgs)Breaking
The parameters changed from (Type) to (ShouldUseConstructorParametersArgs).
public static bool ShouldUseConstructorParameters(Type type)public static bool ShouldUseConstructorParameters(ShouldUseConstructorParametersArgs args)CsvConfigurationrecord38 breaking1 removed37 changed
AllowCommentsBreaking
The init accessor was removed.
public virtual bool AllowComments { get; init; }public virtual bool AllowComments { get; set; }BadDataFoundBreaking
The init accessor was removed.
public virtual BadDataFound BadDataFound { get; init; }public virtual BadDataFound BadDataFound { get; set; }BufferSizeBreaking
The init accessor was removed.
public virtual int BufferSize { get; init; }public virtual int BufferSize { get; set; }CacheFieldsBreaking
The init accessor was removed.
public virtual bool CacheFields { get; init; }public virtual bool CacheFields { get; set; }CommentBreaking
The init accessor was removed.
public virtual char Comment { get; init; }public virtual char Comment { get; set; }CountBytesBreaking
The init accessor was removed.
public virtual bool CountBytes { get; init; }public virtual bool CountBytes { get; set; }DelimiterBreaking
The init accessor was removed.
public virtual string Delimiter { get; init; }public virtual string Delimiter { get; set; }DetectColumnCountChangesBreaking
The init accessor was removed.
public virtual bool DetectColumnCountChanges { get; init; }public virtual bool DetectColumnCountChanges { get; set; }DynamicPropertySortBreaking
The init accessor was removed.
public virtual IComparer<string> DynamicPropertySort { get; init; }public virtual IComparer<string> DynamicPropertySort { get; set; }EncodingBreaking
The init accessor was removed.
public virtual Encoding Encoding { get; init; }public virtual Encoding Encoding { get; set; }EscapeBreaking
The init accessor was removed.
public virtual char Escape { get; init; }public virtual char Escape { get; set; }GetConstructorBreaking
The init accessor was removed.
public virtual GetConstructor GetConstructor { get; init; }public virtual GetConstructor GetConstructor { get; set; }GetDynamicPropertyNameBreaking
The init accessor was removed.
public virtual GetDynamicPropertyName GetDynamicPropertyName { get; init; }public virtual GetDynamicPropertyName GetDynamicPropertyName { get; set; }HasHeaderRecordBreaking
The init accessor was removed.
public virtual bool HasHeaderRecord { get; init; }public virtual bool HasHeaderRecord { get; set; }HeaderValidatedBreaking
The init accessor was removed.
public virtual HeaderValidated HeaderValidated { get; init; }public virtual HeaderValidated HeaderValidated { get; set; }IgnoreBlankLinesBreaking
The init accessor was removed.
public virtual bool IgnoreBlankLines { get; init; }public virtual bool IgnoreBlankLines { get; set; }IgnoreReferencesBreaking
The init accessor was removed.
public virtual bool IgnoreReferences { get; init; }public virtual bool IgnoreReferences { get; set; }IncludePrivateMembersBreaking
The init accessor was removed.
public virtual bool IncludePrivateMembers { get; init; }public virtual bool IncludePrivateMembers { get; set; }InjectionCharactersBreaking
The init accessor was removed.
public virtual char[] InjectionCharacters { get; init; }public virtual char[] InjectionCharacters { get; set; }InjectionEscapeCharacterBreaking
The init accessor was removed.
public virtual char InjectionEscapeCharacter { get; init; }public virtual char InjectionEscapeCharacter { get; set; }LeaveOpenBreaking
The init accessor was removed.
public virtual bool LeaveOpen { get; init; }public virtual bool LeaveOpen { get; set; }LineBreakInQuotedFieldIsBadDataBreaking
The init accessor was removed.
public virtual bool LineBreakInQuotedFieldIsBadData { get; init; }public virtual bool LineBreakInQuotedFieldIsBadData { get; set; }MemberTypesBreaking
The init accessor was removed.
public virtual MemberTypes MemberTypes { get; init; }public virtual MemberTypes MemberTypes { get; set; }MissingFieldFoundBreaking
The init accessor was removed.
public virtual MissingFieldFound MissingFieldFound { get; init; }public virtual MissingFieldFound MissingFieldFound { get; set; }ModeBreaking
The init accessor was removed.
public virtual CsvMode Mode { get; init; }public virtual CsvMode Mode { get; set; }PrepareHeaderForMatchBreaking
The init accessor was removed.
public virtual PrepareHeaderForMatch PrepareHeaderForMatch { get; init; }public virtual PrepareHeaderForMatch PrepareHeaderForMatch { get; set; }ProcessFieldBufferSizeBreaking
The init accessor was removed.
public virtual int ProcessFieldBufferSize { get; init; }public virtual int ProcessFieldBufferSize { get; set; }QuoteBreaking
The init accessor was removed.
public virtual char Quote { get; init; }public virtual char Quote { get; set; }ReadingExceptionOccurredBreaking
The init accessor was removed.
public virtual ReadingExceptionOccurred ReadingExceptionOccurred { get; init; }public virtual ReadingExceptionOccurred ReadingExceptionOccurred { get; set; }ReferenceHeaderPrefixBreaking
The init accessor was removed.
public virtual ReferenceHeaderPrefix ReferenceHeaderPrefix { get; init; }public virtual ReferenceHeaderPrefix ReferenceHeaderPrefix { get; set; }SanitizeForInjectionBreaking
The init accessor was removed.
public virtual bool SanitizeForInjection { get; init; }public virtual bool SanitizeForInjection { get; set; }ShouldQuoteBreaking
The init accessor was removed.
public ShouldQuote ShouldQuote { get; init; }public ShouldQuote ShouldQuote { get; set; }ShouldSkipRecordBreaking
The init accessor was removed.
public virtual ShouldSkipRecord ShouldSkipRecord { get; init; }public virtual ShouldSkipRecord ShouldSkipRecord { get; set; }ShouldUseConstructorParametersBreaking
The init accessor was removed.
public virtual ShouldUseConstructorParameters ShouldUseConstructorParameters { get; init; }public virtual ShouldUseConstructorParameters ShouldUseConstructorParameters { get; set; }TrimOptionsBreaking
The init accessor was removed.
public virtual TrimOptions TrimOptions { get; init; }public virtual TrimOptions TrimOptions { get; set; }UseNewObjectForNullReferenceMembersBreaking
The init accessor was removed.
public virtual bool UseNewObjectForNullReferenceMembers { get; init; }public virtual bool UseNewObjectForNullReferenceMembers { get; set; }WhiteSpaceCharsBreaking
The init accessor was removed.
public virtual char[] WhiteSpaceChars { get; init; }public virtual char[] WhiteSpaceChars { get; set; }Removed