Skip to content

Commit

Permalink
Moved all configuration settings into local fields in CsvReader.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshClose committed Jan 29, 2021
1 parent ceaa383 commit 8c18d04
Showing 1 changed file with 56 additions and 43 deletions.
99 changes: 56 additions & 43 deletions src/CsvHelper/CsvReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@ public class CsvReader : IReader
private readonly Dictionary<string, (string, int)> namedIndexCache = new Dictionary<string, (string, int)>();
private readonly Dictionary<Type, TypeConverterOptions> typeConverterOptionsCache = new Dictionary<Type, TypeConverterOptions>();
private readonly MemberMapData reusableMemberMapData = new MemberMapData(null);
private readonly IReaderConfiguration configuration;
private readonly bool hasHeaderRecord;
private readonly HeaderValidated headerValidated;
private readonly ShouldSkipRecord shouldSkipRecord;
private readonly ReadingExceptionOccurred readingExceptionOccurred;
private readonly CultureInfo cultureInfo;
private readonly bool ignoreBlankLines;
private readonly MissingFieldFound missingFieldFound;
private readonly bool includePrivateMembers;
private readonly PrepareHeaderForMatch prepareHeaderForMatch;

private CsvContext context;
private bool disposed;
Expand All @@ -50,7 +58,7 @@ public class CsvReader : IReader
public virtual CsvContext Context => context;

/// <inheritdoc/>
public virtual IReaderConfiguration Configuration => configuration;
public virtual IReaderConfiguration Configuration { get; private set; }

/// <inheritdoc/>
public virtual IParser Parser => parser;
Expand All @@ -77,24 +85,29 @@ public CsvReader(TextReader reader, CsvConfiguration configuration) : this(new C
/// <param name="parser">The <see cref="IParser" /> used to parse the CSV file.</param>
public CsvReader(IParser parser)
{
configuration = parser.Configuration as IReaderConfiguration;
if (configuration == null)
{
throw new ConfigurationException($"The {nameof(IParser)} configuration must implement {nameof(IReaderConfiguration)} to be used in {nameof(CsvReader)}.");
}

detectColumnCountChanges = configuration.DetectColumnCountChanges;
Configuration = parser.Configuration as IReaderConfiguration ?? throw new ConfigurationException($"The {nameof(IParser)} configuration must implement {nameof(IReaderConfiguration)} to be used in {nameof(CsvReader)}.");

this.parser = parser ?? throw new ArgumentNullException(nameof(parser));
context = parser.Context ?? throw new InvalidOperationException($"For {nameof(IParser)} to be used in {nameof(CsvReader)}, {nameof(IParser.Context)} must also implement {nameof(CsvContext)}.");
context.Reader = this;
recordManager = new Lazy<RecordManager>(() => ObjectResolver.Current.Resolve<RecordManager>(this));

cultureInfo = Configuration.CultureInfo;
detectColumnCountChanges = Configuration.DetectColumnCountChanges;
hasHeaderRecord = Configuration.HasHeaderRecord;
headerValidated = Configuration.HeaderValidated;
ignoreBlankLines = Configuration.IgnoreBlankLines;
includePrivateMembers = Configuration.IncludePrivateMembers;
missingFieldFound = Configuration.MissingFieldFound;
prepareHeaderForMatch = Configuration.PrepareHeaderForMatch;
readingExceptionOccurred = Configuration.ReadingExceptionOccurred;
shouldSkipRecord = Configuration.ShouldSkipRecord;
}

/// <inheritdoc/>
public virtual bool ReadHeader()
{
if (!configuration.HasHeaderRecord)
if (!hasHeaderRecord)
{
throw new ReaderException(context, "Configuration.HasHeaderRecord is false.");
}
Expand All @@ -114,7 +127,7 @@ public virtual void ValidateHeader<T>()
/// <inheritdoc/>
public virtual void ValidateHeader(Type type)
{
if (Configuration.HasHeaderRecord == false)
if (hasHeaderRecord == false)
{
throw new InvalidOperationException($"Validation can't be performed on a the header if no header exists. {nameof(Configuration.HasHeaderRecord)} can't be false.");
}
Expand All @@ -135,7 +148,7 @@ public virtual void ValidateHeader(Type type)
var invalidHeaders = new List<InvalidHeader>();
ValidateHeader(map, invalidHeaders);

Configuration.HeaderValidated?.Invoke(invalidHeaders.ToArray(), context);
headerValidated?.Invoke(invalidHeaders.ToArray(), context);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -221,7 +234,7 @@ public virtual bool Read()
{
hasMoreRecords = parser.Read();
}
while (hasMoreRecords && Configuration.ShouldSkipRecord(parser.Record));
while (hasMoreRecords && shouldSkipRecord(parser.Record));

currentIndex = -1;
hasBeenRead = true;
Expand All @@ -232,7 +245,7 @@ public virtual bool Read()
{
var csvException = new BadDataException(context, "An inconsistent number of columns has been detected.");

if (configuration.ReadingExceptionOccurred?.Invoke(csvException) ?? true)
if (readingExceptionOccurred?.Invoke(csvException) ?? true)
{
throw csvException;
}
Expand All @@ -252,7 +265,7 @@ public virtual async Task<bool> ReadAsync()
{
hasMoreRecords = await parser.ReadAsync();
}
while (hasMoreRecords && Configuration.ShouldSkipRecord(parser.Record));
while (hasMoreRecords && shouldSkipRecord(parser.Record));

currentIndex = -1;
hasBeenRead = true;
Expand All @@ -263,7 +276,7 @@ public virtual async Task<bool> ReadAsync()
{
var csvException = new BadDataException(context, "An inconsistent number of columns has been detected.");

if (configuration.ReadingExceptionOccurred?.Invoke(csvException) ?? true)
if (readingExceptionOccurred?.Invoke(csvException) ?? true)
{
throw csvException;
}
Expand Down Expand Up @@ -320,9 +333,9 @@ public virtual string GetField(int index)

if (index >= parser.Count || index < 0)
{
if (configuration.IgnoreBlankLines)
if (ignoreBlankLines)
{
configuration.MissingFieldFound?.Invoke(null, index, context);
missingFieldFound?.Invoke(null, index, context);
}

return default;
Expand Down Expand Up @@ -397,7 +410,7 @@ public virtual object GetField(Type type, int index, ITypeConverter converter)
reusableMemberMapData.TypeConverter = converter;
if (!typeConverterOptionsCache.TryGetValue(type, out TypeConverterOptions typeConverterOptions))
{
typeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = configuration.CultureInfo }, context.TypeConverterOptionsCache.GetOptions(type));
typeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = cultureInfo }, context.TypeConverterOptionsCache.GetOptions(type));
typeConverterOptionsCache.Add(type, typeConverterOptions);
}

Expand Down Expand Up @@ -460,9 +473,9 @@ public virtual T GetField<T>(int index, ITypeConverter converter)
if (index >= parser.Count || index < 0)
{
currentIndex = index;
if (configuration.IgnoreBlankLines)
if (ignoreBlankLines)
{
configuration.MissingFieldFound?.Invoke(null, index, context);
missingFieldFound?.Invoke(null, index, context);
}

return default;
Expand Down Expand Up @@ -702,7 +715,7 @@ public virtual T GetRecord<T>()
{
CheckHasBeenRead();

if (headerRecord == null && configuration.HasHeaderRecord)
if (headerRecord == null && hasHeaderRecord)
{
ReadHeader();
ValidateHeader<T>();
Expand All @@ -722,7 +735,7 @@ record = recordManager.Value.Create<T>();
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -761,7 +774,7 @@ public virtual object GetRecord(Type type)
{
CheckHasBeenRead();

if (headerRecord == null && configuration.HasHeaderRecord)
if (headerRecord == null && hasHeaderRecord)
{
ReadHeader();
ValidateHeader(type);
Expand All @@ -781,7 +794,7 @@ record = recordManager.Value.Create(type);
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -814,7 +827,7 @@ public virtual IEnumerable<T> GetRecords<T>()
// Don't need to check if it's been read
// since we're doing the reading ourselves.

if (configuration.HasHeaderRecord && headerRecord == null)
if (hasHeaderRecord && headerRecord == null)
{
if (!Read())
{
Expand All @@ -836,7 +849,7 @@ record = recordManager.Value.Create<T>();
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -887,7 +900,7 @@ public virtual IEnumerable<object> GetRecords(Type type)
// Don't need to check if it's been read
// since we're doing the reading ourselves.

if (configuration.HasHeaderRecord && headerRecord == null)
if (hasHeaderRecord && headerRecord == null)
{
if (!Read())
{
Expand All @@ -909,7 +922,7 @@ record = recordManager.Value.Create(type);
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -944,7 +957,7 @@ public virtual IEnumerable<T> EnumerateRecords<T>(T record)
// Don't need to check if it's been read
// since we're doing the reading ourselves.

if (configuration.HasHeaderRecord && headerRecord == null)
if (hasHeaderRecord && headerRecord == null)
{
if (!Read())
{
Expand All @@ -965,7 +978,7 @@ public virtual IEnumerable<T> EnumerateRecords<T>(T record)
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -1001,7 +1014,7 @@ public virtual async IAsyncEnumerable<T> GetRecordsAsync<T>()
// Don't need to check if it's been read
// since we're doing the reading ourselves.

if (configuration.HasHeaderRecord && headerRecord == null)
if (hasHeaderRecord && headerRecord == null)
{
if (!await ReadAsync().ConfigureAwait(false))
{
Expand All @@ -1023,7 +1036,7 @@ record = recordManager.Value.Create<T>();
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -1074,7 +1087,7 @@ public virtual async IAsyncEnumerable<object> GetRecordsAsync(Type type)
// Don't need to check if it's been read
// since we're doing the reading ourselves.

if (configuration.HasHeaderRecord && headerRecord == null)
if (hasHeaderRecord && headerRecord == null)
{
if (!await ReadAsync().ConfigureAwait(false))
{
Expand All @@ -1096,7 +1109,7 @@ record = recordManager.Value.Create(type);
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -1131,7 +1144,7 @@ public virtual async IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record)
// Don't need to check if it's been read
// since we're doing the reading ourselves.

if (configuration.HasHeaderRecord && headerRecord == null)
if (hasHeaderRecord && headerRecord == null)
{
if (!await ReadAsync().ConfigureAwait(false))
{
Expand All @@ -1152,7 +1165,7 @@ public virtual async IAsyncEnumerable<T> EnumerateRecordsAsync<T>(T record)
{
var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);

if (configuration.ReadingExceptionOccurred?.Invoke(csvHelperException) ?? true)
if (readingExceptionOccurred?.Invoke(csvHelperException) ?? true)
{
if (ex is CsvHelperException)
{
Expand Down Expand Up @@ -1187,7 +1200,7 @@ public virtual int GetFieldIndex(string[] names, int index = 0, bool isTryGet =
throw new ArgumentNullException(nameof(names));
}

if (!configuration.HasHeaderRecord)
if (!hasHeaderRecord)
{
throw new ReaderException(context, "There is no header record to determine the index by name.");
}
Expand All @@ -1211,7 +1224,7 @@ public virtual int GetFieldIndex(string[] names, int index = 0, bool isTryGet =
{
var n = names[i];
// Get the list of indexes for this name.
var fieldName = configuration.PrepareHeaderForMatch(n, i);
var fieldName = prepareHeaderForMatch(n, i);
if (namedIndexes.ContainsKey(fieldName))
{
name = fieldName;
Expand All @@ -1225,7 +1238,7 @@ public virtual int GetFieldIndex(string[] names, int index = 0, bool isTryGet =
// It doesn't exist. The field is missing.
if (!isTryGet && !isOptional)
{
configuration.MissingFieldFound?.Invoke(names, index, context);
missingFieldFound?.Invoke(names, index, context);
}

return -1;
Expand All @@ -1249,7 +1262,7 @@ public virtual bool CanRead(MemberMap memberMap)
cantRead = cantRead ||
// Properties that don't have a public setter
// and we are honoring the accessor modifier.
property.GetSetMethod() == null && !configuration.IncludePrivateMembers ||
property.GetSetMethod() == null && !includePrivateMembers ||
// Properties that don't have a setter at all.
property.GetSetMethod(true) == null;
}
Expand All @@ -1268,7 +1281,7 @@ public virtual bool CanRead(MemberReferenceMap memberReferenceMap)
cantRead =
// Properties that don't have a public setter
// and we are honoring the accessor modifier.
property.GetSetMethod() == null && !configuration.IncludePrivateMembers ||
property.GetSetMethod() == null && !includePrivateMembers ||
// Properties that don't have a setter at all.
property.GetSetMethod(true) == null;
}
Expand Down Expand Up @@ -1327,7 +1340,7 @@ protected virtual void ParseNamedIndexes()

for (var i = 0; i < headerRecord.Length; i++)
{
var name = configuration.PrepareHeaderForMatch(headerRecord[i], i);
var name = prepareHeaderForMatch(headerRecord[i], i);
if (namedIndexes.ContainsKey(name))
{
namedIndexes[name].Add(i);
Expand Down

0 comments on commit 8c18d04

Please sign in to comment.