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 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/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(); 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