diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index fd58dfb0..54aa4c43 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -24,7 +24,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v4 with: - dotnet-version: '8.0.x' + dotnet-version: '9.0.x' - name: Display dotnet version run: dotnet --version diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 831ba07a..c2fe2483 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v4 with: - dotnet-version: '8.0.x' + dotnet-version: '9.0.x' - name: Display dotnet version run: dotnet --version diff --git a/CsvHelper.sln b/CsvHelper.sln deleted file mode 100644 index 98749be6..00000000 --- a/CsvHelper.sln +++ /dev/null @@ -1,59 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.2.32210.308 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6445B2A3-9E05-4ABF-AE2E-C875773B277A}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - .gitignore = .gitignore - README.markdown = README.markdown - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CsvHelper", "src\CsvHelper\CsvHelper.csproj", "{ECF9E2A8-3592-4DA4-9FAB-BFA56AD44B9C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CsvHelper.Tests", "tests\CsvHelper.Tests\CsvHelper.Tests.csproj", "{6859ECD8-81AE-4E74-A926-5726AAD7EE81}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CsvHelper.Performance", "performance\CsvHelper.Performance\CsvHelper.Performance.csproj", "{F1C225F2-92FC-41BB-94BF-733454DD2A9D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestApp", "TestApp\TestApp.csproj", "{8C33E5DF-2F2E-4FE3-91DD-C6683B310221}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {ECF9E2A8-3592-4DA4-9FAB-BFA56AD44B9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ECF9E2A8-3592-4DA4-9FAB-BFA56AD44B9C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ECF9E2A8-3592-4DA4-9FAB-BFA56AD44B9C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ECF9E2A8-3592-4DA4-9FAB-BFA56AD44B9C}.Release|Any CPU.Build.0 = Release|Any CPU - {6859ECD8-81AE-4E74-A926-5726AAD7EE81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6859ECD8-81AE-4E74-A926-5726AAD7EE81}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6859ECD8-81AE-4E74-A926-5726AAD7EE81}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6859ECD8-81AE-4E74-A926-5726AAD7EE81}.Release|Any CPU.Build.0 = Release|Any CPU - {F1C225F2-92FC-41BB-94BF-733454DD2A9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F1C225F2-92FC-41BB-94BF-733454DD2A9D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F1C225F2-92FC-41BB-94BF-733454DD2A9D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F1C225F2-92FC-41BB-94BF-733454DD2A9D}.Release|Any CPU.Build.0 = Release|Any CPU - {8C33E5DF-2F2E-4FE3-91DD-C6683B310221}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8C33E5DF-2F2E-4FE3-91DD-C6683B310221}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8C33E5DF-2F2E-4FE3-91DD-C6683B310221}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8C33E5DF-2F2E-4FE3-91DD-C6683B310221}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {7F48D3EE-214D-45F4-AC6A-3E95C3A25E9F} - EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection -EndGlobal diff --git a/CsvHelper.slnx b/CsvHelper.slnx new file mode 100644 index 00000000..c9115162 --- /dev/null +++ b/CsvHelper.slnx @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/TestApp/TestApp.csproj b/TestApp/TestApp.csproj index c1d8fad4..81170744 100644 --- a/TestApp/TestApp.csproj +++ b/TestApp/TestApp.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 enable enable true diff --git a/performance/CsvHelper.Performance/CsvHelper.Performance.csproj b/performance/CsvHelper.Performance/CsvHelper.Performance.csproj index 2944d35c..92fcef3d 100644 --- a/performance/CsvHelper.Performance/CsvHelper.Performance.csproj +++ b/performance/CsvHelper.Performance/CsvHelper.Performance.csproj @@ -2,12 +2,12 @@ Exe - net8.0 + net9.0 enable - + diff --git a/src/CsvHelper/Configuration/ConfigurationFunctions.cs b/src/CsvHelper/Configuration/ConfigurationFunctions.cs index eb6c9c1b..c17102c3 100644 --- a/src/CsvHelper/Configuration/ConfigurationFunctions.cs +++ b/src/CsvHelper/Configuration/ConfigurationFunctions.cs @@ -8,8 +8,6 @@ namespace CsvHelper.Configuration; /// Holds the default callback methods for delegate members of CsvHelper.Configuration.Configuration. public static class ConfigurationFunctions { - private static readonly char[] lineEndingChars = ['\r', '\n']; - /// /// Throws a MissingFieldException. /// diff --git a/src/CsvHelper/Configuration/CsvConfiguration.cs b/src/CsvHelper/Configuration/CsvConfiguration.cs index 092e48e9..1b4c7ede 100644 --- a/src/CsvHelper/Configuration/CsvConfiguration.cs +++ b/src/CsvHelper/Configuration/CsvConfiguration.cs @@ -47,9 +47,6 @@ public record CsvConfiguration : IReaderConfiguration, IWriterConfiguration /// public virtual bool DetectColumnCountChanges { get; set; } - /// - public virtual IComparer DynamicPropertySort { get; set; } - /// public virtual Encoding Encoding { get; set; } = Encoding.UTF8; @@ -65,18 +62,6 @@ public record CsvConfiguration : IReaderConfiguration, IWriterConfiguration /// public virtual bool IgnoreBlankLines { get; set; } = true; - /// - public virtual bool IgnoreReferences { get; set; } - - /// - public virtual bool IncludePrivateMembers { get; set; } - - /// - public virtual char[] InjectionCharacters { get; set; } = ['=', '@', '+', '-']; - - /// - public virtual char InjectionEscapeCharacter { get; set; } = '\t'; - /// public bool IsNewLineSet { get; private set; } @@ -122,10 +107,7 @@ public virtual string NewLine public virtual TrimOptions TrimOptions { get; set; } /// - public virtual bool UseNewObjectForNullReferenceMembers { get; set; } = true; - - /// - public virtual char[] WhiteSpaceChars { get; set; } = new char[] { ' ' }; + public virtual char[] WhiteSpaceChars { get; set; } = [' ']; /// /// Initializes a new instance of the class diff --git a/src/CsvHelper/Configuration/IReaderConfiguration.cs b/src/CsvHelper/Configuration/IReaderConfiguration.cs index 7165cb17..c183d991 100644 --- a/src/CsvHelper/Configuration/IReaderConfiguration.cs +++ b/src/CsvHelper/Configuration/IReaderConfiguration.cs @@ -52,13 +52,6 @@ public interface IReaderConfiguration : IParserConfiguration /// ShouldSkipRecord ShouldSkipRecord { get; } - /// - /// Gets a value indicating if private - /// member should be read from and written to. - /// true to include private member, otherwise false. Default is false. - /// - bool IncludePrivateMembers { get; } - /// /// Gets a value indicating whether changes in the column /// count should be detected. If true, a diff --git a/src/CsvHelper/CsvHelper.csproj b/src/CsvHelper/CsvHelper.csproj index 431507d4..9107b88e 100644 --- a/src/CsvHelper/CsvHelper.csproj +++ b/src/CsvHelper/CsvHelper.csproj @@ -8,7 +8,7 @@ CsvHelper - net8.0 + net9.0 CsvHelper en-US true @@ -46,7 +46,7 @@ - + \ No newline at end of file diff --git a/src/CsvHelper/CsvReader.cs b/src/CsvHelper/CsvReader.cs index c3edf90d..71a25074 100644 --- a/src/CsvHelper/CsvReader.cs +++ b/src/CsvHelper/CsvReader.cs @@ -19,10 +19,8 @@ public class CsvReader : IReader private readonly bool hasHeaderRecord; 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; @@ -79,11 +77,9 @@ public CsvReader(IParser 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; - cultureInfo = Configuration.CultureInfo; detectColumnCountChanges = Configuration.DetectColumnCountChanges; hasHeaderRecord = Configuration.HasHeaderRecord; ignoreBlankLines = Configuration.IgnoreBlankLines; - includePrivateMembers = Configuration.IncludePrivateMembers; missingFieldFound = Configuration.MissingFieldFound; prepareHeaderForMatch = Configuration.PrepareHeaderForMatch; readingExceptionOccurred = Configuration.ReadingExceptionOccurred; @@ -261,16 +257,13 @@ public virtual string GetField(string name, int index) /// public virtual int GetFieldIndex(string name, int index = 0, bool isTryGet = false) { - return GetFieldIndex(new[] { name }, index, isTryGet); + return GetFieldIndex([name], index, isTryGet); } /// public virtual int GetFieldIndex(string[] names, int index = 0, bool isTryGet = false, bool isOptional = false) { - if (names == null) - { - throw new ArgumentNullException(nameof(names)); - } + ArgumentNullException.ThrowIfNull(names); if (!hasHeaderRecord) { @@ -284,9 +277,9 @@ public virtual int GetFieldIndex(string[] names, int index = 0, bool isTryGet = // Caching the named index speeds up mappings that use ConvertUsing tremendously. var nameKey = string.Join("_", names) + index; - if (namedIndexCache.ContainsKey(nameKey)) + if (namedIndexCache.TryGetValue(nameKey, out (string, int) value)) { - (var cachedName, var cachedIndex) = namedIndexCache[nameKey]; + (var cachedName, var cachedIndex) = value; return namedIndexes[cachedName][cachedIndex]; } @@ -376,13 +369,13 @@ protected virtual void ParseNamedIndexes() { var args = new PrepareHeaderForMatchArgs(headerRecord[i], i); var name = prepareHeaderForMatch(args); - if (namedIndexes.ContainsKey(name)) + if (namedIndexes.TryGetValue(name, out List value)) { - namedIndexes[name].Add(i); + value.Add(i); } else { - namedIndexes[name] = new List { i }; + namedIndexes[name] = [i]; } } } diff --git a/src/CsvHelper/CsvWriter.cs b/src/CsvHelper/CsvWriter.cs index 141c4703..8a7ff9ca 100644 --- a/src/CsvHelper/CsvWriter.cs +++ b/src/CsvHelper/CsvWriter.cs @@ -10,15 +10,12 @@ namespace CsvHelper; public class CsvWriter : IDisposable { private readonly TextWriter writer; - private string newLine = "\r\n"; - private string quoteString = "\""; - private string delimiter = ";"; - private readonly bool leaveOpen; - private char quote = '"'; + private readonly string newLine = "\r\n"; + private readonly string quoteString = "\""; + private readonly string delimiter = ";"; + private readonly char quote = '"'; private readonly char comment = '#'; private readonly string escapeQuoteString; - private readonly char[] injectionCharacters; - private readonly char injectionEscapeCharacter; private int row = 1; private int index; @@ -47,7 +44,7 @@ public class CsvWriter : IDisposable public CsvWriter(TextWriter writer) { this.writer = writer; - escapeQuoteString = new string(new[] { '"' }); + escapeQuoteString = new string(['"']); buffer = new char[bufferSize]; } @@ -82,7 +79,7 @@ public virtual void WriteHeader(string[] headers) headerRecord.Add(header); } - HeaderRecord = headerRecord.ToArray(); + HeaderRecord = [.. headerRecord]; } /// @@ -139,7 +136,7 @@ private bool ShouldQuote(string field) ( field.Contains(quote) // Contains quote || field[0] == ' ' // Starts with a space - || field[field.Length - 1] == ' ' // Ends with a space + || field[^1] == ' ' // Ends with a space || (delimiter.Length > 0 && field.Contains(delimiter)) // Contains delimiter || field.Contains(newLine) // Contains newline ); @@ -147,28 +144,6 @@ private bool ShouldQuote(string field) return shouldQuote; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected virtual string SanitizeForInjection(string field) - { - if (string.IsNullOrEmpty(field)) - { - return field; - } - - if (ArrayHelper.Contains(injectionCharacters, field[0])) - { - return injectionEscapeCharacter + field; - } - - if (field[0] == quote && ArrayHelper.Contains(injectionCharacters, field[1])) - { - return field[0].ToString() + injectionEscapeCharacter.ToString() + field.Substring(1); - } - - return field; - } - /// public virtual void NextRecord() { @@ -266,11 +241,7 @@ protected virtual void Dispose(bool disposing) if (disposing) { // Dispose managed state (managed objects) - - if (!leaveOpen) - { - writer.Dispose(); - } + writer.Dispose(); } // Free unmanaged resources (unmanaged objects) and override finalizer @@ -301,11 +272,7 @@ protected virtual async ValueTask DisposeAsync(bool disposing) if (disposing) { // Dispose managed state (managed objects) - - if (!leaveOpen) - { - await writer.DisposeAsync().ConfigureAwait(false); - } + await writer.DisposeAsync().ConfigureAwait(false); } // Free unmanaged resources (unmanaged objects) and override finalizer diff --git a/src/CsvHelper/packages.lock.json b/src/CsvHelper/packages.lock.json index 6b85a9b1..48329d1f 100644 --- a/src/CsvHelper/packages.lock.json +++ b/src/CsvHelper/packages.lock.json @@ -1,12 +1,12 @@ { "version": 1, "dependencies": { - "net8.0": { + "net9.0": { "Microsoft.NET.ILLink.Tasks": { "type": "Direct", - "requested": "[8.0.4, )", - "resolved": "8.0.4", - "contentHash": "PZb5nfQ+U19nhnmnR9T1jw+LTmozhuG2eeuzuW5A7DqxD/UXW2ucjmNJqnqOuh8rdPzM3MQXoF8AfFCedJdCUw==" + "requested": "[9.0.10, )", + "resolved": "9.0.10", + "contentHash": "sseaSJcBxKEpkc59hnB00b3NmJdGvJLfj74HK+nucHxERxbZSUREuWKjC9ywc+HdzJvJyiP2eiyEOROaGSfcPw==" }, "Microsoft.SourceLink.GitHub": { "type": "Direct", @@ -20,9 +20,9 @@ }, "Nerdbank.GitVersioning": { "type": "Direct", - "requested": "[3.6.133, )", - "resolved": "3.6.133", - "contentHash": "VZWMd5YAeDxpjWjAP/X6bAxnRMiEf6tES/ITN0X5CHJgkWLLeHGmEALivmTAfYM6P+P/3Szy6VCITUAkqjcHVw==" + "requested": "[3.8.118, )", + "resolved": "3.8.118", + "contentHash": "cRaG+ICcECG+CzbtQyUV2WftH7yl2B02AjYGGNScXx8TwYavZYwhCewBTiC0qTcsac7m6AzBUYna5xzBWmTGYw==" }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", diff --git a/tests/CsvHelper.Tests/CsvHelper.Tests.csproj b/tests/CsvHelper.Tests/CsvHelper.Tests.csproj index 71258014..37691459 100644 --- a/tests/CsvHelper.Tests/CsvHelper.Tests.csproj +++ b/tests/CsvHelper.Tests/CsvHelper.Tests.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable @@ -11,16 +11,16 @@ - - + + - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/CsvHelper.Tests/CsvReaderTests.cs b/tests/CsvHelper.Tests/CsvReaderTests.cs index 87c67882..4bf032a7 100644 --- a/tests/CsvHelper.Tests/CsvReaderTests.cs +++ b/tests/CsvHelper.Tests/CsvReaderTests.cs @@ -243,11 +243,6 @@ private struct TestStruct public string Name { get; set; } } - private class OnlyFields - { - public string Name; - } - private class TestBoolean { public bool BoolColumn { get; set; }