From a5579d7b8cc41eb81570c31be039895ac2724474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 11:52:13 +0200 Subject: [PATCH 1/9] display json and xml-like files more comfortably --- .editorconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.editorconfig b/.editorconfig index fbddd8c..d28d7d6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,12 @@ indent_size = 4 indent_style = space indent_size = 2 +[*.json] +indent_size = 2 + +[*.{xml,csproj,slnx}] +indent_size = 2 + [*.cs] dotnet_diagnostic.CA1034.severity = none From 62384c8865c3acf7f6a1e31e8751aa84e921b62a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 12:18:36 +0200 Subject: [PATCH 2/9] stop targeting netstandard1.3 to prevent warnings --- archive/NMoneys.Exchange/NMoneys.Exchange.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archive/NMoneys.Exchange/NMoneys.Exchange.csproj b/archive/NMoneys.Exchange/NMoneys.Exchange.csproj index 7d2500f..93439bd 100644 --- a/archive/NMoneys.Exchange/NMoneys.Exchange.csproj +++ b/archive/NMoneys.Exchange/NMoneys.Exchange.csproj @@ -1,7 +1,7 @@ - netstandard1.3 + netstandard2.0 true From 6e03761505f64a2a8633eadaddba5317032d5e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 12:20:35 +0200 Subject: [PATCH 3/9] small fix in build script when no previous built performed --- scripts/NMoneys.build.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/NMoneys.build.ps1 b/scripts/NMoneys.build.ps1 index b78ce4b..d87df85 100644 --- a/scripts/NMoneys.build.ps1 +++ b/scripts/NMoneys.build.ps1 @@ -18,7 +18,7 @@ task Clean { exec { & dotnet clean -c $configuration -v $verbosity --nologo $BASE_DIR } # clear built packages Join-Path $BASE_DIR src NMoneys bin $configuration | - Get-ChildItem | + Get-ChildItem -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '.nupkg' } | Remove-Item # clear release folder @@ -44,7 +44,7 @@ task Test { & dotnet run --no-build -c $configuration -v $verbosity --project $tests_dir -- ` --results-directory $test_results_dir ` --coverage --coverage-output-format cobertura --coverage-output "$test_project.cobertura.xml" ` - --settings $runsettings_path + --settings $runsettings_path } } From 954588af92831c018a1f8eb9a9f2442476dd9ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 12:23:25 +0200 Subject: [PATCH 4/9] target latest SDK --- global.json | 10 ++++++++++ .../NMoneys.Serialization.Tests.csproj | 2 +- tests/NMoneys.Tests/NMoneys.Tests.csproj | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 global.json diff --git a/global.json b/global.json new file mode 100644 index 0000000..666cdf2 --- /dev/null +++ b/global.json @@ -0,0 +1,10 @@ +{ + "sdk": { + "version": "10.0.202", + "allowPrerelease": false, + "rollForward": "latestFeature" + }, + "test": { + "runner": "VSTest" + } +} diff --git a/tests/NMoneys.Serialization.Tests/NMoneys.Serialization.Tests.csproj b/tests/NMoneys.Serialization.Tests/NMoneys.Serialization.Tests.csproj index ea764f8..eb3781e 100644 --- a/tests/NMoneys.Serialization.Tests/NMoneys.Serialization.Tests.csproj +++ b/tests/NMoneys.Serialization.Tests/NMoneys.Serialization.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/tests/NMoneys.Tests/NMoneys.Tests.csproj b/tests/NMoneys.Tests/NMoneys.Tests.csproj index 888ddcf..6d7c353 100644 --- a/tests/NMoneys.Tests/NMoneys.Tests.csproj +++ b/tests/NMoneys.Tests/NMoneys.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable From b0c45e1b3f8e8a1daf4ac6ee1be34604e3a67efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 12:24:15 +0200 Subject: [PATCH 5/9] deprecate BGN for EUR --- src/NMoneys/CurrencyIsoCode.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NMoneys/CurrencyIsoCode.cs b/src/NMoneys/CurrencyIsoCode.cs index 25e0133..a05515e 100644 --- a/src/NMoneys/CurrencyIsoCode.cs +++ b/src/NMoneys/CurrencyIsoCode.cs @@ -186,13 +186,14 @@ public enum CurrencyIsoCode : ushort /// /// Bulgarian Lev /// - [CanonicalCulture("bg-BG")] + [CanonicalCulture("bg-BG"), Obsolete("deprecated in favor of EUR")] [Info( englishName: "Bulgarian Lev", nativeName: "Български лев", symbol: "лв.", significantDecimalDigits: 2, decimalSeparator: ",", groupSeparator: "\u00a0", groupSizes: new byte[] { 0 }, - positivePattern: 3, negativePattern: 8 + positivePattern: 3, negativePattern: 8, + isObsolete: true )] BGN = 975, From 7b48a5e3a4ac5ee456c995e4f075c0899eabd444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 12:46:24 +0200 Subject: [PATCH 6/9] bump up version --- .../NMoneys.Serialization.csproj | 4 +- src/NMoneys/NMoneys.csproj | 108 +++++++++--------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/NMoneys.Serialization/NMoneys.Serialization.csproj b/src/NMoneys.Serialization/NMoneys.Serialization.csproj index e5ada77..a4d36dc 100644 --- a/src/NMoneys.Serialization/NMoneys.Serialization.csproj +++ b/src/NMoneys.Serialization/NMoneys.Serialization.csproj @@ -23,8 +23,8 @@ 5.0.0 - 5.0.0.0 - 5.0.0.0 + $(Version).0 + $(Version).0 diff --git a/src/NMoneys/NMoneys.csproj b/src/NMoneys/NMoneys.csproj index 03453a4..f04333a 100644 --- a/src/NMoneys/NMoneys.csproj +++ b/src/NMoneys/NMoneys.csproj @@ -1,54 +1,54 @@ - - - - net6.0 - enable - enable - - true - true - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - - - - Implementation of the Money Value Object to support representing moneys in the currencies defined in the ISO 4217 standard, - operations over monetary quantities and formatting of its representation. - NMoneys - Copyright © Daniel Gonzalez Garcia 2011 - - - - Daniel González García and contributors - https://github.com/dgg/nmoneys - https://github.com/dgg/nmoneys.git - git - LICENSE - https://github.com/dgg/nmoneys/blob/9bb8f1883b1b34496ee859dd3d48919544161dc7/NMoneys_logo.png - NMoneys.logo.png - README.md - .net;dotnet;C#;currency;money;iso;monetary;quantity;iso4217 - - - - 7.4.0 - 7.4.0.0 - 7.4.0.0 - 7.4.0 - - - - - <_Parameter1>$(AssemblyName).Tests - - - <_Parameter1>false - - - - - - - - - + + + + net6.0 + enable + enable + + true + true + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + Implementation of the Money Value Object to support representing moneys in the currencies defined in the ISO 4217 standard, + operations over monetary quantities and formatting of its representation. + NMoneys + Copyright © Daniel Gonzalez Garcia 2011 + + + + Daniel González García and contributors + https://github.com/dgg/nmoneys + https://github.com/dgg/nmoneys.git + git + LICENSE + https://github.com/dgg/nmoneys/blob/9bb8f1883b1b34496ee859dd3d48919544161dc7/NMoneys_logo.png + NMoneys.logo.png + README.md + .net;dotnet;C#;currency;money;iso;monetary;quantity;iso4217 + + + + 7.5.0 + $(Version).0 + $(Version).0 + $(Version) + + + + + <_Parameter1>$(AssemblyName).Tests + + + <_Parameter1>false + + + + + + + + + From 6055fd5ba346b8d7952bdda9e403ab2203064a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 14:37:49 +0200 Subject: [PATCH 7/9] add attributes to clarify types and overloads for span parsing --- src/NMoneys/Money.Parsing.cs | 83 +++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/src/NMoneys/Money.Parsing.cs b/src/NMoneys/Money.Parsing.cs index ee845c4..1cd9579 100644 --- a/src/NMoneys/Money.Parsing.cs +++ b/src/NMoneys/Money.Parsing.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; @@ -8,18 +9,22 @@ public partial struct Money /// /// Converts the string representation of a monetary quantity () to its equivalent. /// + /// Monetary quantity representation to be parsed. /// The currency value does not contain enumeration information. /// The amount value is not in the correct format. /// The currency value does not contain a defined . /// Components of the representation are missing. /// Monetary quantity equivalent to its representation. [Pure] - public static Money Parse(string quantity) + public static Money Parse(string quantity) => Parse(quantity.AsSpan()); + + /// + [Pure] + public static Money Parse(ReadOnlySpan quantity) { - ReadOnlySpan span = quantity.AsSpan(); - CurrencyIsoCode currency = Enum.Parse(span[..3], ignoreCase: false); + CurrencyIsoCode currency = Enum.Parse(quantity[..3], ignoreCase: false); currency.AssertDefined(); - decimal amount = decimal.Parse(span[4..], + decimal amount = decimal.Parse(quantity[4..], style: NumberStyles.Float, provider: NumberFormatInfo.InvariantInfo); return new Money(amount, currency); @@ -33,25 +38,22 @@ public static Money Parse(string quantity) /// if the conversion succeeded, or null if the conversion failed. /// true if was converted successfully; otherwise, false. [Pure] - public static bool TryParse(string quantity, out Money? money) + public static bool TryParse(string quantity, out Money? money) => TryParse(quantity.AsSpan(), out money); + + /// + [Pure] + public static bool TryParse(ReadOnlySpan quantity, [NotNullWhen(true)] out Money? money) { - ReadOnlySpan span = quantity.AsSpan(); - try + if (quantity.Length >= 5) { - if (Enum.TryParse(span[..3], out CurrencyIsoCode currencyCode) && + if (Enum.TryParse(quantity[..3], out CurrencyIsoCode currencyCode) && currencyCode.CheckDefined() && - decimal.TryParse(span[4..], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out decimal amount)) + decimal.TryParse(quantity[4..], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out decimal amount)) { money = new Money(amount, currencyCode); return true; } } -#pragma warning disable CA1031 - catch - { - // span indexing operation can throw - } -#pragma warning restore CA1031 money = null; return false; @@ -70,10 +72,11 @@ public static bool TryParse(string quantity, out Money? money) /// is null. /// [Pure] - public static Money Parse(string s, Currency currency) - { - return Parse(s, NumberStyles.Currency, currency); - } + public static Money Parse(string s, Currency currency) => Parse(s, NumberStyles.Currency, currency); + + /// + [Pure] + public static Money Parse(ReadOnlySpan s, Currency currency) => Parse(s, NumberStyles.Currency, currency); /// /// Converts the string representation of a monetary quantity to its equivalent @@ -94,7 +97,11 @@ public static Money Parse(string s, Currency currency) /// /// [Pure] - public static Money Parse(string s, NumberStyles style, Currency currency) + public static Money Parse(string s, NumberStyles style, Currency currency) => Parse(s.AsSpan(), style, currency); + + /// + [Pure] + public static Money Parse(ReadOnlySpan s, NumberStyles style, Currency currency) { decimal amount = decimal.Parse(s, style, currency); @@ -116,10 +123,13 @@ public static Money Parse(string s, NumberStyles style, Currency currency) /// true if s was converted successfully; otherwise, false. /// [Pure] - public static bool TryParse(string s, Currency currency, out Money? money) - { - return TryParse(s, NumberStyles.Currency, currency, out money); - } + public static bool TryParse(string s, Currency currency, [NotNullWhen(true)] out Money? money) => + TryParse(s, NumberStyles.Currency, currency, out money); + + /// + [Pure] + public static bool TryParse(ReadOnlySpan s, Currency currency, [NotNullWhen(true)] out Money? money) => + TryParse(s, NumberStyles.Currency, currency, out money); /// /// Converts the string representation of a monetary quantity to its equivalent @@ -143,9 +153,13 @@ public static bool TryParse(string s, Currency currency, out Money? money) /// is null. /// [Pure] - public static bool TryParse(string s, NumberStyles style, Currency currency, out Money? money) + public static bool TryParse(string s, NumberStyles style, Currency currency, [NotNullWhen(true)] out Money? money) => + TryParse(s.AsSpan(), style, currency, out money); + + /// + [Pure] + public static bool TryParse(ReadOnlySpan s, NumberStyles style, Currency currency, [NotNullWhen(true)] out Money? money) { - ArgumentNullException.ThrowIfNull(currency, nameof(currency)); money = tryParse(s, style, currency.FormatInfo, currency.IsoCode); return money.HasValue; } @@ -178,14 +192,16 @@ public static bool TryParse(string s, NumberStyles style, Currency currency, out /// This parameter is passed uninitialized. /// /// true if s was converted successfully; otherwise, false. - /// or is null. [Pure] public static bool TryParse(string s, NumberStyles style, NumberFormatInfo numberFormatInfo, Currency currency, - out Money? money) - { - ArgumentNullException.ThrowIfNull(numberFormatInfo, nameof(numberFormatInfo)); - ArgumentNullException.ThrowIfNull(currency, nameof(currency)); + [NotNullWhen(true)] out Money? money) => TryParse(s.AsSpan(), style, numberFormatInfo, currency, out money); + /// + [Pure] + public static bool TryParse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo numberFormatInfo, + Currency currency, + [NotNullWhen(true)] out Money? money) + { var mergedNumberFormatInfo = (NumberFormatInfo)numberFormatInfo.Clone(); mergedNumberFormatInfo.CurrencySymbol = currency.Symbol; @@ -194,11 +210,10 @@ public static bool TryParse(string s, NumberStyles style, NumberFormatInfo numbe return money.HasValue; } - private static Money? tryParse(string s, NumberStyles style, NumberFormatInfo formatProvider, + private static Money? tryParse(ReadOnlySpan s, NumberStyles style, NumberFormatInfo formatProvider, CurrencyIsoCode currency) { - decimal amount; - bool result = decimal.TryParse(s, style, formatProvider, out amount); + bool result = decimal.TryParse(s, style, formatProvider, out var amount); return result ? new Money(amount, currency) : null; } } From 9c00796d547e0572c82f3aa393cf983bb7fb6eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 14:59:00 +0200 Subject: [PATCH 8/9] add more code analysis for Try() methods --- src/NMoneys/Currency.Creation.cs | 8 ++++---- src/NMoneys/Money.Parsing.cs | 9 ++++++--- src/NMoneys/Support/InfoAttribute.cs | 3 ++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/NMoneys/Currency.Creation.cs b/src/NMoneys/Currency.Creation.cs index a567c87..fe1e310 100644 --- a/src/NMoneys/Currency.Creation.cs +++ b/src/NMoneys/Currency.Creation.cs @@ -133,7 +133,7 @@ public static Currency Get(RegionInfo region) /// The currency represented by /// has not been properly configured by the library implementor. Please, log a issue. [Pure] - public static bool TryGet(CurrencyIsoCode code, out Currency? currency) + public static bool TryGet(CurrencyIsoCode code, [NotNullWhen(true)] out Currency? currency) { bool tryGet = false; currency = null; @@ -168,7 +168,7 @@ public static bool TryGet(CurrencyIsoCode code, out Currency? currency) /// lookup succeeds, or null if the lookup fails. /// true if was looked up successfully; otherwise, false. [Pure] - public static bool TryGet(string threeLetterIsoSymbol, out Currency? currency) + public static bool TryGet(string threeLetterIsoSymbol, [NotNullWhen(true)] out Currency? currency) { bool tryGet = false; currency = null; @@ -202,7 +202,7 @@ public static bool TryGet(string threeLetterIsoSymbol, out Currency? currency) /// the if the lookup succeeds, or null if the lookup fails. /// true if was looked up successfully; otherwise, false. [Pure] - public static bool TryGet([NotNull] CultureInfo culture, out Currency? currency) + public static bool TryGet([NotNull] CultureInfo culture, [NotNullWhen(true)] out Currency? currency) { bool tryGet = false; currency = null; @@ -235,7 +235,7 @@ public static bool TryGet([NotNull] CultureInfo culture, out Currency? currency) /// the if the lookup succeeds, or null if the lookup fails. /// true if was looked up successfully; otherwise, false. [Pure] - public static bool TryGet([NotNull] RegionInfo region, out Currency? currency) + public static bool TryGet([NotNull] RegionInfo region, [NotNullWhen(true)] out Currency? currency) { return TryGet(region.ISOCurrencySymbol, out currency); } diff --git a/src/NMoneys/Money.Parsing.cs b/src/NMoneys/Money.Parsing.cs index 1cd9579..ca58199 100644 --- a/src/NMoneys/Money.Parsing.cs +++ b/src/NMoneys/Money.Parsing.cs @@ -38,7 +38,8 @@ public static Money Parse(ReadOnlySpan quantity) /// if the conversion succeeded, or null if the conversion failed. /// true if was converted successfully; otherwise, false. [Pure] - public static bool TryParse(string quantity, out Money? money) => TryParse(quantity.AsSpan(), out money); + public static bool TryParse(string quantity, [NotNullWhen(true)] out Money? money) => + TryParse(quantity.AsSpan(), out money); /// [Pure] @@ -153,12 +154,14 @@ public static bool TryParse(ReadOnlySpan s, Currency currency, [NotNullWhe /// is null. /// [Pure] - public static bool TryParse(string s, NumberStyles style, Currency currency, [NotNullWhen(true)] out Money? money) => + public static bool TryParse(string s, NumberStyles style, Currency currency, + [NotNullWhen(true)] out Money? money) => TryParse(s.AsSpan(), style, currency, out money); /// [Pure] - public static bool TryParse(ReadOnlySpan s, NumberStyles style, Currency currency, [NotNullWhen(true)] out Money? money) + public static bool TryParse(ReadOnlySpan s, NumberStyles style, Currency currency, + [NotNullWhen(true)] out Money? money) { money = tryParse(s, style, currency.FormatInfo, currency.IsoCode); return money.HasValue; diff --git a/src/NMoneys/Support/InfoAttribute.cs b/src/NMoneys/Support/InfoAttribute.cs index 7359da8..eba8ae6 100644 --- a/src/NMoneys/Support/InfoAttribute.cs +++ b/src/NMoneys/Support/InfoAttribute.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace NMoneys.Support; @@ -73,7 +74,7 @@ public static InfoAttribute GetFrom(CurrencyIsoCode code) return attribute; } - public static bool TryGetFrom(CurrencyIsoCode code, out InfoAttribute? attribute) + public static bool TryGetFrom(CurrencyIsoCode code, [NotNullWhen(true)] out InfoAttribute? attribute) { FieldInfo field = code.FieldOf(); attribute = field.GetCustomAttribute(); From 8b3f8567cdec8fd4e8aaa1ec4a98340cad69b5c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Gonz=C3=A1lez=20Garc=C3=ADa?= Date: Wed, 22 Apr 2026 15:06:43 +0200 Subject: [PATCH 9/9] use version of sdk specified in global.json --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d37618..f7d4b75 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.406 + global-json-path: ${{ github.workspace }}/global.json #- name: Info # run: dotnet --info - name: Restore