From a702e0b4ded04ec89c915e56dd355d95b3eec9c2 Mon Sep 17 00:00:00 2001 From: Michele Bastione Date: Mon, 21 Sep 2026 22:50:27 +0200 Subject: [PATCH 1/3] Updated projects in the solution to target .NET 11 - Added .NET 11 target to the MiniExcel source main projects and test projects - Replaced the .NET 9 target with the .NET 11 target in the benchmark project - Added .NET 11 as one of the dotnet versions to build and test for in github actions --- .github/workflows/dotnet.yml | 1 + benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj | 2 +- src/Directory.Build.props | 4 ++-- tests/MiniExcel.Csv.Tests/MiniExcel.Csv.Tests.csproj | 2 +- tests/MiniExcel.OpenXml.Tests/MiniExcel.OpenXml.Tests.csproj | 2 +- tests/MiniExcel.Tests.Common/MiniExcel.Tests.Common.csproj | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index fed4199b..fee1ec54 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -19,6 +19,7 @@ jobs: 8.0.x 9.0.x 10.0.x + 11.0.x - name: Restore dependencies run: dotnet restore env: diff --git a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj index 108cf0d2..48d76133 100644 --- a/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj +++ b/benchmarks/MiniExcel.Benchmarks/MiniExcel.Benchmarks.csproj @@ -2,7 +2,7 @@ Exe - net9.0;net10.0 + net10.0;net11.0 enable enable latest diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 40ed5466..1e8ae4cd 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,11 +1,11 @@ - netstandard2.0;net8.0;net9.0;net10.0 + netstandard2.0;net8.0;net9.0;net10.0;net11.0 2.0.0-preview.4 enable enable - 14 + preview diff --git a/tests/MiniExcel.Csv.Tests/MiniExcel.Csv.Tests.csproj b/tests/MiniExcel.Csv.Tests/MiniExcel.Csv.Tests.csproj index f061e911..fba820ec 100644 --- a/tests/MiniExcel.Csv.Tests/MiniExcel.Csv.Tests.csproj +++ b/tests/MiniExcel.Csv.Tests/MiniExcel.Csv.Tests.csproj @@ -1,7 +1,7 @@ - net8.0;net9.0;net10.0 + net8.0;net9.0;net10.0;net11.0 enable enable $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA1849;CA2000;CA2007;CA2208 diff --git a/tests/MiniExcel.OpenXml.Tests/MiniExcel.OpenXml.Tests.csproj b/tests/MiniExcel.OpenXml.Tests/MiniExcel.OpenXml.Tests.csproj index c6967037..c13050e3 100644 --- a/tests/MiniExcel.OpenXml.Tests/MiniExcel.OpenXml.Tests.csproj +++ b/tests/MiniExcel.OpenXml.Tests/MiniExcel.OpenXml.Tests.csproj @@ -1,7 +1,7 @@  - net8.0;net9.0;net10.0 + net8.0;net9.0;net10.0;net11.0 enable enable $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA1849;CA2000;CA2007;CA2208 diff --git a/tests/MiniExcel.Tests.Common/MiniExcel.Tests.Common.csproj b/tests/MiniExcel.Tests.Common/MiniExcel.Tests.Common.csproj index a961a4fb..254d3993 100644 --- a/tests/MiniExcel.Tests.Common/MiniExcel.Tests.Common.csproj +++ b/tests/MiniExcel.Tests.Common/MiniExcel.Tests.Common.csproj @@ -1,7 +1,7 @@  - net8.0;net9.0;net10.0 + net8.0;net9.0;net10.0;net11.0 enable enable MiniExcelLib.Tests.Common From ba0ff7b028d679f4dbc1f9a74564cb07cf55f77b Mon Sep 17 00:00:00 2001 From: Michele Bastione Date: Mon, 21 Sep 2026 23:06:30 +0200 Subject: [PATCH 2/3] Addressed a breaking change regarding double to decimal conversion introduced in .NET 11 In .NET 11 conversion APIs such as `new Decimal(double value)` or `Convert.ToDecimal(double value)` among others have been changed to approximate the resulting value more accurately. Unfortunately this is a significant breaking change for us as we relied upon this truncation to discard unwanted decimal digits when mapping doubles (our default numeric type) to decimals. Hence a workaround was added to ensure backwards compatibility was mantained. --- src/MiniExcel.Core/Helpers/Polyfills.cs | 20 +++++++++++ src/MiniExcel.Core/MiniExcelDataReaderBase.cs | 7 +++- .../Reflection/MiniExcelMapper.cs | 33 ++++++++++++++++++- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/MiniExcel.Core/Helpers/Polyfills.cs b/src/MiniExcel.Core/Helpers/Polyfills.cs index ecc97456..1e65a2c7 100644 --- a/src/MiniExcel.Core/Helpers/Polyfills.cs +++ b/src/MiniExcel.Core/Helpers/Polyfills.cs @@ -155,6 +155,26 @@ public static ValueTask CreateAsync(Stream stream, ZipArchiveMode mo } } #endif + +#if NET11_0_OR_GREATER + extension(Convert) + { + /// Converts the specified double value to decimal using the same approximation applied by versions of .NET no greater than 10. + /// + /// In .NET 11 conversion APIs such as and among others + /// have been changed to approximate the resulting value more accurately. Unfortunately this is a significant breaking change for us + /// as we relied upon this truncation to discard unwanted decimal digits when mapping doubles (our default numeric type) to decimals. + /// This method is therefore a workaround to ensure backwards compatibility with previous versions of the library. + /// + [EditorBrowsable(EditorBrowsableState.Advanced)] + public static decimal ToDecimalWithLegacyApproximation(double value) + { + Span text = stackalloc char[32]; + value.TryFormat(text, out var length, "G15", CultureInfo.InvariantCulture); + return decimal.Parse(text[..length], NumberStyles.Float, CultureInfo.InvariantCulture); + } + } +#endif } #if NETSTANDARD2_0 diff --git a/src/MiniExcel.Core/MiniExcelDataReaderBase.cs b/src/MiniExcel.Core/MiniExcelDataReaderBase.cs index bb6acd77..98c017dc 100644 --- a/src/MiniExcel.Core/MiniExcelDataReaderBase.cs +++ b/src/MiniExcel.Core/MiniExcelDataReaderBase.cs @@ -136,7 +136,12 @@ public virtual byte GetByte(int i) => GetValue(i) is { } value public virtual decimal GetDecimal(int i) => GetValue(i) switch { - decimal d => d, + decimal dec => dec, +#if NET11_0_OR_GREATER + double f64 => Convert.ToDecimalWithLegacyApproximation(f64), +#else + double f64 => Convert.ToDecimal(f64, CultureInfo.InvariantCulture), +#endif null => throw new InvalidOperationException("The value is null"), var value => Convert.ToDecimal(value, MiniExcelConfiguration.Culture) }; diff --git a/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs b/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs index 597f29ff..75bb0959 100644 --- a/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs +++ b/src/MiniExcel.Core/Reflection/MiniExcelMapper.cs @@ -214,7 +214,11 @@ public static partial class MiniExcelMapper else if (map.ExcludeNullableType == typeof(double)) { - if (double.TryParse(Convert.ToString(itemValue, config.Culture), NumberStyles.Any, config.Culture, out var doubleValue)) + if (itemValue is double f64) + { + newValue = f64; + } + else if (double.TryParse(Convert.ToString(itemValue, config.Culture), NumberStyles.Any, config.Culture, out var doubleValue)) { newValue = doubleValue; } @@ -227,6 +231,33 @@ public static partial class MiniExcelMapper } } + else if (map.ExcludeNullableType == typeof(decimal)) + { + if (itemValue is decimal dec) + { + newValue = dec; + } + else if (itemValue is double f64) + { +#if NET11_0_OR_GREATER + newValue = Convert.ToDecimalWithLegacyApproximation(f64); +#else + newValue = Convert.ToDecimal(f64, CultureInfo.InvariantCulture); +#endif + } + else if (decimal.TryParse(Convert.ToString(itemValue, config.Culture), NumberStyles.Any, config.Culture, out var decimalValue)) + { + newValue = decimalValue; + } + else + { + var invariantString = Convert.ToString(itemValue, CultureInfo.InvariantCulture); + newValue = decimal.TryParse(invariantString, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) + ? value + : throw new InvalidCastException(); + } + } + else if (map.ExcludeNullableType == typeof(bool)) { var vs = itemValue?.ToString(); From 07aa9c3b70b10a8d5da4e2e6eda8df59d1163cbf Mon Sep 17 00:00:00 2001 From: Michele Bastione Date: Tue, 22 Sep 2026 00:20:30 +0200 Subject: [PATCH 3/3] Updating codeql and benchmark workflows --- .github/workflows/benchmark.yml | 12 ++++++------ .github/workflows/codeql-analysis.yml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index a51e5749..ccac33e3 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -17,7 +17,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 10.0.x + dotnet-version: 11.0.x - name: Restore dependencies run: dotnet restore working-directory: ./benchmarks/MiniExcel.Benchmarks @@ -25,7 +25,7 @@ jobs: run: dotnet build --no-restore working-directory: ./benchmarks/MiniExcel.Benchmarks - name: Benchmark - run: dotnet run -c Release -f net10.0 + run: dotnet run -c Release -f net11.0 working-directory: ./benchmarks/MiniExcel.Benchmarks env: BenchmarkMode: Automatic @@ -47,7 +47,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 10.0.x + dotnet-version: 11.0.x - name: Restore dependencies run: dotnet restore working-directory: ./benchmarks/MiniExcel.Benchmarks @@ -55,7 +55,7 @@ jobs: run: dotnet build --no-restore working-directory: ./benchmarks/MiniExcel.Benchmarks - name: Benchmark - run: dotnet run -c Release -f net10.0 + run: dotnet run -c Release -f net11.0 working-directory: ./benchmarks/MiniExcel.Benchmarks env: BenchmarkMode: Automatic @@ -77,7 +77,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 10.0.x + dotnet-version: 11.0.x - name: Restore dependencies run: dotnet restore working-directory: ./benchmarks/MiniExcel.Benchmarks @@ -85,7 +85,7 @@ jobs: run: dotnet build --no-restore working-directory: ./benchmarks/MiniExcel.Benchmarks - name: Benchmark - run: dotnet run -c Release -f net10.0 + run: dotnet run -c Release -f net11.0 working-directory: ./benchmarks/MiniExcel.Benchmarks env: BenchmarkMode: Automatic diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 4790c226..31231a8a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -43,7 +43,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 10.0.x + dotnet-version: 11.0.x - name: Restore dependencies run: dotnet restore