From 2a1cd4fda8a4a8e649910d16b4dfa1ce7ae63543 Mon Sep 17 00:00:00 2001
From: chai <215380520@qq.com>
Date: Fri, 12 May 2023 09:24:40 +0800
Subject: *misc
---
.../CsvHelper-master/src/CsvHelper/CsvReader.cs | 1419 ++++++++++++++++++++
1 file changed, 1419 insertions(+)
create mode 100644 ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs
(limited to 'ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs')
diff --git a/ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs
new file mode 100644
index 0000000..2b8ee84
--- /dev/null
+++ b/ThirdParty/CsvHelper-master/src/CsvHelper/CsvReader.cs
@@ -0,0 +1,1419 @@
+// Copyright 2009-2022 Josh Close
+// This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0.
+// See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0.
+// https://github.com/JoshClose/CsvHelper
+using System;
+using System.Collections.Generic;
+using System.IO;
+using CsvHelper.Configuration;
+using CsvHelper.TypeConversion;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using CsvHelper.Expressions;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Configuration;
+
+namespace CsvHelper
+{
+ ///
+ /// Reads data that was parsed from .
+ ///
+ public class CsvReader : IReader
+ {
+ private readonly Lazy recordManager;
+ private readonly bool detectColumnCountChanges;
+ private readonly Dictionary> namedIndexes = new Dictionary>();
+ private readonly Dictionary namedIndexCache = new Dictionary();
+ private readonly Dictionary typeConverterOptionsCache = new Dictionary();
+ private readonly MemberMapData reusableMemberMapData = new MemberMapData(null);
+ 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;
+ private IParser parser;
+ private int columnCount;
+ private int currentIndex = -1;
+ private bool hasBeenRead;
+ private string[]? headerRecord;
+
+ ///
+ public virtual int ColumnCount => columnCount;
+
+ ///
+ public virtual int CurrentIndex => currentIndex;
+
+ ///
+ public virtual string[]? HeaderRecord => headerRecord;
+
+ ///
+ public virtual CsvContext Context => context;
+
+ ///
+ public virtual IReaderConfiguration Configuration { get; private set; }
+
+ ///
+ public virtual IParser Parser => parser;
+
+ ///
+ /// Creates a new CSV reader using the given .
+ ///
+ /// The reader.
+ /// The culture.
+ /// true to leave the open after the object is disposed, otherwise false.
+ public CsvReader(TextReader reader, CultureInfo culture, bool leaveOpen = false) : this(new CsvParser(reader, culture, leaveOpen)) { }
+
+ ///
+ /// Creates a new CSV reader using the given and
+ /// and as the default parser.
+ ///
+ /// The reader.
+ /// The configuration.
+ /// true to leave the open after the object is disposed, otherwise false.
+ public CsvReader(TextReader reader, IReaderConfiguration configuration, bool leaveOpen = false) : this(new CsvParser(reader, configuration, leaveOpen)) { }
+
+ ///
+ /// Creates a new CSV reader using the given .
+ ///
+ /// The used to parse the CSV file.
+ public CsvReader(IParser parser)
+ {
+ 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(() => ObjectResolver.Current.Resolve(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;
+ }
+
+ ///
+ public virtual bool ReadHeader()
+ {
+ if (!hasHeaderRecord)
+ {
+ throw new ReaderException(context, "Configuration.HasHeaderRecord is false.");
+ }
+
+ headerRecord = parser.Record;
+ ParseNamedIndexes();
+
+ return headerRecord != null;
+ }
+
+ ///
+ /// Validates the header to be of the given type.
+ ///
+ /// The expected type of the header
+ public virtual void ValidateHeader()
+ {
+ ValidateHeader(typeof(T));
+ }
+
+ ///
+ /// Validates the header to be of the given type.
+ ///
+ /// The expected type of the header.
+ public virtual void ValidateHeader(Type type)
+ {
+ 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.");
+ }
+
+ CheckHasBeenRead();
+
+ if (headerRecord == null)
+ {
+ throw new InvalidOperationException($"The header must be read before it can be validated.");
+ }
+
+ if (context.Maps[type] == null)
+ {
+ context.Maps.Add(context.AutoMap(type));
+ }
+
+ var map = context.Maps[type];
+ var invalidHeaders = new List();
+ ValidateHeader(map, invalidHeaders);
+
+ var args = new HeaderValidatedArgs(invalidHeaders.ToArray(), context);
+ headerValidated?.Invoke(args);
+ }
+
+ ///
+ /// Validates the header to be of the given type.
+ ///
+ /// The mapped classes.
+ /// The invalid headers.
+ protected virtual void ValidateHeader(ClassMap map, List invalidHeaders)
+ {
+ foreach (var parameter in map.ParameterMaps)
+ {
+ if (parameter.Data.Ignore)
+ {
+ continue;
+ }
+
+ if (parameter.Data.IsConstantSet)
+ {
+ // If ConvertUsing and Constant don't require a header.
+ continue;
+ }
+
+ if (parameter.Data.IsIndexSet && !parameter.Data.IsNameSet)
+ {
+ // If there is only an index set, we don't want to validate the header name.
+ continue;
+ }
+
+ if (parameter.ConstructorTypeMap != null)
+ {
+ ValidateHeader(parameter.ConstructorTypeMap, invalidHeaders);
+ }
+ else if (parameter.ReferenceMap != null)
+ {
+ ValidateHeader(parameter.ReferenceMap.Data.Mapping, invalidHeaders);
+ }
+ else
+ {
+ var index = GetFieldIndex(parameter.Data.Names, parameter.Data.NameIndex, true);
+ var isValid = index != -1 || parameter.Data.IsOptional;
+ if (!isValid)
+ {
+ invalidHeaders.Add(new InvalidHeader { Index = parameter.Data.NameIndex, Names = parameter.Data.Names.ToList() });
+ }
+ }
+ }
+
+ foreach (var memberMap in map.MemberMaps)
+ {
+ if (memberMap.Data.Ignore || !CanRead(memberMap))
+ {
+ continue;
+ }
+
+ if (memberMap.Data.ReadingConvertExpression != null || memberMap.Data.IsConstantSet)
+ {
+ // If ConvertUsing and Constant don't require a header.
+ continue;
+ }
+
+ if (memberMap.Data.IsIndexSet && !memberMap.Data.IsNameSet)
+ {
+ // If there is only an index set, we don't want to validate the header name.
+ continue;
+ }
+
+ var index = GetFieldIndex(memberMap.Data.Names, memberMap.Data.NameIndex, true);
+ var isValid = index != -1 || memberMap.Data.IsOptional;
+ if (!isValid)
+ {
+ invalidHeaders.Add(new InvalidHeader { Index = memberMap.Data.NameIndex, Names = memberMap.Data.Names.ToList() });
+ }
+ }
+
+ foreach (var referenceMap in map.ReferenceMaps)
+ {
+ if (!CanRead(referenceMap))
+ {
+ continue;
+ }
+
+ ValidateHeader(referenceMap.Data.Mapping, invalidHeaders);
+ }
+ }
+
+ ///
+ public virtual bool Read()
+ {
+ // Don't forget about the async method below!
+
+ bool hasMoreRecords;
+ do
+ {
+ hasMoreRecords = parser.Read();
+ hasBeenRead = true;
+ }
+ while (hasMoreRecords && (shouldSkipRecord?.Invoke(new ShouldSkipRecordArgs(this)) ?? false));
+
+ currentIndex = -1;
+
+ if (detectColumnCountChanges && hasMoreRecords)
+ {
+ if (columnCount > 0 && columnCount != parser.Count)
+ {
+ var csvException = new BadDataException(string.Empty, parser.RawRecord, context, "An inconsistent number of columns has been detected.");
+
+ var args = new ReadingExceptionOccurredArgs(csvException);
+ if (readingExceptionOccurred?.Invoke(args) ?? true)
+ {
+ throw csvException;
+ }
+ }
+
+ columnCount = parser.Count;
+ }
+
+ return hasMoreRecords;
+ }
+
+ ///
+ public virtual async Task ReadAsync()
+ {
+ bool hasMoreRecords;
+ do
+ {
+ hasMoreRecords = await parser.ReadAsync().ConfigureAwait(false);
+ hasBeenRead = true;
+ }
+ while (hasMoreRecords && (shouldSkipRecord?.Invoke(new ShouldSkipRecordArgs(this)) ?? false));
+
+ currentIndex = -1;
+
+ if (detectColumnCountChanges && hasMoreRecords)
+ {
+ if (columnCount > 0 && columnCount != parser.Count)
+ {
+ var csvException = new BadDataException(string.Empty, parser.RawRecord, context, "An inconsistent number of columns has been detected.");
+
+ var args = new ReadingExceptionOccurredArgs(csvException);
+ if (readingExceptionOccurred?.Invoke(args) ?? true)
+ {
+ throw csvException;
+ }
+ }
+
+ columnCount = parser.Count;
+ }
+
+ return hasMoreRecords;
+ }
+
+ ///
+ public virtual string? this[int index]
+ {
+ get
+ {
+ CheckHasBeenRead();
+
+ return GetField(index);
+ }
+ }
+
+ ///
+ public virtual string? this[string name]
+ {
+ get
+ {
+ CheckHasBeenRead();
+
+ return GetField(name);
+ }
+ }
+
+ ///
+ public virtual string? this[string name, int index]
+ {
+ get
+ {
+ CheckHasBeenRead();
+
+ return GetField(name, index);
+ }
+ }
+
+ ///
+ public virtual string? GetField(int index)
+ {
+ CheckHasBeenRead();
+
+ // Set the current index being used so we
+ // have more information if an error occurs
+ // when reading records.
+ currentIndex = index;
+
+ if (index >= parser.Count || index < 0)
+ {
+ var args = new MissingFieldFoundArgs(null, index, context);
+ missingFieldFound?.Invoke(args);
+ return default;
+ }
+
+ var field = parser[index];
+
+ return field;
+ }
+
+ ///
+ public virtual string? GetField(string name)
+ {
+ CheckHasBeenRead();
+
+ var index = GetFieldIndex(name);
+ if (index < 0)
+ {
+ return null;
+ }
+
+ return GetField(index);
+ }
+
+ ///
+ public virtual string? GetField(string name, int index)
+ {
+ CheckHasBeenRead();
+
+ var fieldIndex = GetFieldIndex(name, index);
+ if (fieldIndex < 0)
+ {
+ return null;
+ }
+
+ return GetField(fieldIndex);
+ }
+
+ ///
+ public virtual object? GetField(Type type, int index)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter(type);
+ return GetField(type, index, converter);
+ }
+
+ ///
+ public virtual object? GetField(Type type, string name)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter(type);
+ return GetField(type, name, converter);
+ }
+
+ ///
+ public virtual object? GetField(Type type, string name, int index)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter(type);
+ return GetField(type, name, index, converter);
+ }
+
+ ///
+ public virtual object? GetField(Type type, int index, ITypeConverter converter)
+ {
+ CheckHasBeenRead();
+
+ reusableMemberMapData.Index = index;
+ reusableMemberMapData.TypeConverter = converter;
+ if (!typeConverterOptionsCache.TryGetValue(type, out TypeConverterOptions typeConverterOptions))
+ {
+ typeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = cultureInfo }, context.TypeConverterOptionsCache.GetOptions(type));
+ typeConverterOptionsCache.Add(type, typeConverterOptions);
+ }
+
+ reusableMemberMapData.TypeConverterOptions = typeConverterOptions;
+
+ var field = GetField(index);
+ return converter.ConvertFromString(field, this, reusableMemberMapData);
+ }
+
+ ///
+ public virtual object? GetField(Type type, string name, ITypeConverter converter)
+ {
+ CheckHasBeenRead();
+
+ var index = GetFieldIndex(name);
+ return GetField(type, index, converter);
+ }
+
+ ///
+ public virtual object? GetField(Type type, string name, int index, ITypeConverter converter)
+ {
+ CheckHasBeenRead();
+
+ var fieldIndex = GetFieldIndex(name, index);
+ return GetField(type, fieldIndex, converter);
+ }
+
+ ///
+ public virtual T? GetField(int index)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter();
+ return GetField(index, converter);
+ }
+
+ ///
+ public virtual T? GetField(string name)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter();
+ return GetField(name, converter);
+ }
+
+ ///
+ public virtual T? GetField(string name, int index)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter();
+ return GetField(name, index, converter);
+ }
+
+ ///
+ public virtual T? GetField(int index, ITypeConverter converter)
+ {
+ CheckHasBeenRead();
+
+ if (index >= parser.Count || index < 0)
+ {
+ currentIndex = index;
+ var args = new MissingFieldFoundArgs(null, index, context);
+ missingFieldFound?.Invoke(args);
+
+ return default;
+ }
+
+ return (T)GetField(typeof(T), index, converter);
+ }
+
+ ///
+ public virtual T? GetField(string name, ITypeConverter converter)
+ {
+ CheckHasBeenRead();
+
+ var index = GetFieldIndex(name);
+ return GetField(index, converter);
+ }
+
+ ///
+ public virtual T? GetField(string name, int index, ITypeConverter converter)
+ {
+ CheckHasBeenRead();
+
+ var fieldIndex = GetFieldIndex(name, index);
+ return GetField(fieldIndex, converter);
+ }
+
+ ///
+ public virtual T? GetField(int index) where TConverter : ITypeConverter
+ {
+ CheckHasBeenRead();
+
+ var converter = ObjectResolver.Current.Resolve();
+ return GetField(index, converter);
+ }
+
+ ///
+ public virtual T? GetField(string name) where TConverter : ITypeConverter
+ {
+ CheckHasBeenRead();
+
+ var converter = ObjectResolver.Current.Resolve();
+ return GetField(name, converter);
+ }
+
+ ///
+ public virtual T? GetField(string name, int index) where TConverter : ITypeConverter
+ {
+ CheckHasBeenRead();
+
+ var converter = ObjectResolver.Current.Resolve();
+ return GetField(name, index, converter);
+ }
+
+ ///
+ public virtual bool TryGetField(Type type, int index, out object? field)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter(type);
+ return TryGetField(type, index, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(Type type, string name, out object? field)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter(type);
+ return TryGetField(type, name, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(Type type, string name, int index, out object? field)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter(type);
+ return TryGetField(type, name, index, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(Type type, int index, ITypeConverter converter, out object? field)
+ {
+ CheckHasBeenRead();
+
+ // TypeConverter.IsValid() just wraps a
+ // ConvertFrom() call in a try/catch, so lets not
+ // do it twice and just do it ourselves.
+ try
+ {
+ field = GetField(type, index, converter);
+ return true;
+ }
+ catch
+ {
+ field = type.GetTypeInfo().IsValueType ? ObjectResolver.Current.Resolve(type) : null;
+ return false;
+ }
+ }
+
+ ///
+ public virtual bool TryGetField(Type type, string name, ITypeConverter converter, out object? field)
+ {
+ CheckHasBeenRead();
+
+ var index = GetFieldIndex(name, isTryGet: true);
+ if (index == -1)
+ {
+ field = type.GetTypeInfo().IsValueType ? ObjectResolver.Current.Resolve(type) : null;
+ return false;
+ }
+
+ return TryGetField(type, index, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(Type type, string name, int index, ITypeConverter converter, out object? field)
+ {
+ CheckHasBeenRead();
+
+ var fieldIndex = GetFieldIndex(name, index, true);
+ if (fieldIndex == -1)
+ {
+ field = type.GetTypeInfo().IsValueType ? ObjectResolver.Current.Resolve(type) : null;
+ return false;
+ }
+
+ return TryGetField(type, fieldIndex, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(int index, out T? field)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter();
+ return TryGetField(index, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(string name, out T? field)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter();
+ return TryGetField(name, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(string name, int index, out T? field)
+ {
+ CheckHasBeenRead();
+
+ var converter = context.TypeConverterCache.GetConverter();
+ return TryGetField(name, index, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(int index, ITypeConverter converter, out T? field)
+ {
+ CheckHasBeenRead();
+
+ // TypeConverter.IsValid() just wraps a
+ // ConvertFrom() call in a try/catch, so lets not
+ // do it twice and just do it ourselves.
+ try
+ {
+ field = GetField(index, converter);
+ return true;
+ }
+ catch
+ {
+ field = default;
+ return false;
+ }
+ }
+
+ ///
+ public virtual bool TryGetField(string name, ITypeConverter converter, out T? field)
+ {
+ CheckHasBeenRead();
+
+ var index = GetFieldIndex(name, isTryGet: true);
+ if (index == -1)
+ {
+ field = default;
+ return false;
+ }
+
+ return TryGetField(index, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(string name, int index, ITypeConverter converter, out T? field)
+ {
+ CheckHasBeenRead();
+
+ var fieldIndex = GetFieldIndex(name, index, true);
+ if (fieldIndex == -1)
+ {
+ field = default;
+ return false;
+ }
+
+ return TryGetField(fieldIndex, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(int index, out T? field) where TConverter : ITypeConverter
+ {
+ CheckHasBeenRead();
+
+ var converter = ObjectResolver.Current.Resolve();
+ return TryGetField(index, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(string name, out T? field) where TConverter : ITypeConverter
+ {
+ CheckHasBeenRead();
+
+ var converter = ObjectResolver.Current.Resolve();
+ return TryGetField(name, converter, out field);
+ }
+
+ ///
+ public virtual bool TryGetField(string name, int index, out T? field) where TConverter : ITypeConverter
+ {
+ CheckHasBeenRead();
+
+ var converter = ObjectResolver.Current.Resolve();
+ return TryGetField(name, index, converter, out field);
+ }
+
+ ///
+ public virtual T? GetRecord()
+ {
+ CheckHasBeenRead();
+
+ if (headerRecord == null && hasHeaderRecord)
+ {
+ ReadHeader();
+ ValidateHeader();
+
+ if (!Read())
+ {
+ return default;
+ }
+ }
+
+ T record;
+ try
+ {
+ record = recordManager.Value.Create();
+ }
+ catch (Exception ex)
+ {
+ var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);
+
+ var args = new ReadingExceptionOccurredArgs(csvHelperException);
+ if (readingExceptionOccurred?.Invoke(args) ?? true)
+ {
+ if (ex is CsvHelperException)
+ {
+ throw;
+ }
+ else
+ {
+ throw csvHelperException;
+ }
+ }
+
+ record = default;
+ }
+
+ return record;
+ }
+
+ ///
+ public virtual T? GetRecord(T anonymousTypeDefinition)
+ {
+ if (anonymousTypeDefinition == null)
+ {
+ throw new ArgumentNullException(nameof(anonymousTypeDefinition));
+ }
+
+ if (!anonymousTypeDefinition.GetType().IsAnonymous())
+ {
+ throw new ArgumentException($"Argument is not an anonymous type.", nameof(anonymousTypeDefinition));
+ }
+
+ return GetRecord();
+ }
+
+ ///
+ public virtual object? GetRecord(Type type)
+ {
+ CheckHasBeenRead();
+
+ if (headerRecord == null && hasHeaderRecord)
+ {
+ ReadHeader();
+ ValidateHeader(type);
+
+ if (!Read())
+ {
+ return null;
+ }
+ }
+
+ object record;
+ try
+ {
+ record = recordManager.Value.Create(type);
+ }
+ catch (Exception ex)
+ {
+ var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);
+
+ var args = new ReadingExceptionOccurredArgs(csvHelperException);
+ if (readingExceptionOccurred?.Invoke(args) ?? true)
+ {
+ if (ex is CsvHelperException)
+ {
+ throw;
+ }
+ else
+ {
+ throw csvHelperException;
+ }
+ }
+
+ record = default;
+ }
+
+ return record;
+ }
+
+ ///
+ public virtual IEnumerable GetRecords()
+ {
+ if (disposed)
+ {
+ throw new ObjectDisposedException(nameof(CsvReader),
+ "GetRecords() returns an IEnumerable that yields records. This means that the method isn't actually called until " +
+ "you try and access the values. e.g. .ToList() Did you create CsvReader inside a using block and are now trying to access " +
+ "the records outside of that using block?"
+ );
+ }
+
+ // Don't need to check if it's been read
+ // since we're doing the reading ourselves.
+
+ if (hasHeaderRecord && headerRecord == null)
+ {
+ if (!Read())
+ {
+ yield break;
+ }
+
+ ReadHeader();
+ ValidateHeader();
+ }
+
+ while (Read())
+ {
+ T record;
+ try
+ {
+ record = recordManager.Value.Create();
+ }
+ catch (Exception ex)
+ {
+ var csvHelperException = ex as CsvHelperException ?? new ReaderException(context, "An unexpected error occurred.", ex);
+
+ var args = new ReadingExceptionOccurredArgs(csvHelperException);
+ if (readingExceptionOccurred?.Invoke(args) ?? true)
+ {
+ if (ex is CsvHelperException)
+ {
+ throw;
+ }
+ else
+ {
+ throw csvHelperException;
+ }
+ }
+
+ // If the callback doesn't throw, keep going.
+ continue;
+ }
+
+ yield return record;
+ }
+ }
+
+ ///
+ public virtual IEnumerable GetRecords(T anonymousTypeDefinition)
+ {
+ if (anonymousTypeDefinition == null)
+ {
+ throw new ArgumentNullException(nameof(anonymousTypeDefinition));
+ }
+
+ if (!anonymousTypeDefinition.GetType().IsAnonymous())
+ {
+ throw new ArgumentException($"Argument is not an anonymous type.", nameof(anonymousTypeDefinition));
+ }
+
+ return GetRecords();
+ }
+
+ ///
+ public virtual IEnumerable