Skip to content

Commit aa0a263

Browse files
authored
Merge branch 'main' into dependabot/nuget/Microsoft.NET.Test.Sdk-17.10.0
2 parents f6e901e + 5b541d9 commit aa0a263

File tree

15 files changed

+500
-35
lines changed

15 files changed

+500
-35
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: publish SmartEnum.GuardClauses to nuget
2+
on:
3+
workflow_dispatch:
4+
push:
5+
branches:
6+
- main # Your default release branch
7+
paths:
8+
- 'src/SmartEnum.GuardClauses/**'
9+
jobs:
10+
publish:
11+
name: list SmartEnum.GuardClauses on nuget.org
12+
runs-on: windows-latest
13+
steps:
14+
- uses: actions/checkout@v2
15+
16+
# Required for a specific dotnet version that doesn't come with ubuntu-latest / windows-latest
17+
# Visit bit.ly/2synnZl to see the list of SDKs that are pre-installed with ubuntu-latest / windows-latest
18+
- name: Setup .NET Core
19+
uses: actions/setup-dotnet@v3
20+
with:
21+
dotnet-version: |
22+
6.0.x
23+
7.0.x
24+
8.0.x
25+
26+
# Publish
27+
- name: publish on version change
28+
uses: alirezanet/publish-nuget@v3.0.0
29+
with:
30+
PROJECT_FILE_PATH: src/SmartEnum.GuardClauses/SmartEnum.GuardClauses.csproj # Relative to repository root
31+
VERSION_FILE_PATH: Directory.Build.props # Filepath with version info, relative to repository root. Defaults to project file
32+
VERSION_REGEX: <Version>(.*)<\/Version> # Regex pattern to extract version info in a capturing group
33+
TAG_COMMIT: true # Flag to enable / disable git tagging
34+
TAG_FORMAT: SmartEnumGuardClauses-v* # Format of the git tag, [*] gets replaced with version
35+
NUGET_KEY: ${{secrets.NUGET_API_KEY}} # nuget.org API key

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<PackageProjectUrl>https://github.com/ardalis/SmartEnum</PackageProjectUrl>
1010
<PublishRepositoryUrl>true</PublishRepositoryUrl>
1111
<PackageLicenseExpression>MIT</PackageLicenseExpression>
12-
<TargetFrameworks>net7.0;net6.0;net8.0;netstandard2.1</TargetFrameworks>
12+
<TargetFrameworks>net7.0;net6.0;net8.0;netstandard2.0</TargetFrameworks>
1313
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1414
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
1515
<Version>8.0.0</Version>
@@ -35,4 +35,4 @@
3535
up $(IsStableBuild) automatically; property is also used to control prerelease branding.
3636
-->
3737
</PropertyGroup>
38-
</Project>
38+
</Project>

Directory.Packages.props

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
55
<ItemGroup>
6+
<PackageVersion Include="Ardalis.GuardClauses" Version="4.5.0" />
67
<PackageVersion Include="AutoFixture" Version="4.18.1" />
7-
<PackageVersion Include="BenchmarkDotNet" Version="0.13.10" />
8+
<PackageVersion Include="BenchmarkDotNet" Version="0.13.12" />
89
<PackageVersion Include="Constant" Version="2.0.4" />
9-
<PackageVersion Include="coverlet.collector" Version="3.2.0" />
10-
<PackageVersion Include="coverlet.msbuild" Version="3.2.0" />
10+
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
11+
<PackageVersion Include="coverlet.msbuild" Version="6.0.2" />
1112
<PackageVersion Include="Dapper" Version="2.1.28" />
12-
<PackageVersion Include="Enums.NET" Version="4.0.1" />
13-
<PackageVersion Include="FluentAssertions" Version="6.11.0" />
14-
<PackageVersion Include="MessagePack" Version="2.4.59" />
13+
<PackageVersion Include="Enums.NET" Version="5.0.0" />
14+
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
15+
<PackageVersion Include="MessagePack" Version="2.5.140" />
1516
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
1617
<PackageVersion Include="Microsoft.Data.Sqlite" Version="7.0.13" />
1718
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="7.0.13" />
@@ -20,16 +21,16 @@
2021
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
2122
<PackageVersion Include="Moq" Version="4.18.4" />
2223
<PackageVersion Include="Newtonsoft.Json" Version="13.0.2" />
23-
<PackageVersion Include="protobuf-net" Version="3.2.26" />
24+
<PackageVersion Include="protobuf-net" Version="3.2.30" />
25+
<PackageVersion Include="SonarAnalyzer.CSharp" Version="9.12.0.78982" />
2426
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
25-
<PackageVersion Include="System.Text.Json" Version="8.0.2" />
27+
<PackageVersion Include="System.Text.Json" Version="8.0.4" />
2628
<PackageVersion Include="Utf8Json" Version="1.3.7" />
2729
<PackageVersion Include="xunit" Version="2.7.0" />
28-
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
30+
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.1" />
2931
</ItemGroup>
30-
3132
<ItemGroup>
3233
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
33-
<GlobalPackageReference Include="SonarAnalyzer.CSharp" Version="9.17.0.82934" PrivateAssets="All" />
34+
<GlobalPackageReference Include="SonarAnalyzer.CSharp" Version="9.17.0.82934" PrivateAssets="All" />
3435
</ItemGroup>
3536
</Project>

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* [Persisting with EF Core 2.1 or higher](#persisting-with-ef-core-21-or-higher)
2727
* [Using SmartEnum.EFCore](#using-smartenumefcore)
2828
* [AutoFixture support](#autofixture-support)
29-
* [Json.NET support](#jsonnet-support)
29+
* [Json support](#jsonnet-support)
3030
* [Dapper support](#dapper-support)
3131
* [DapperSmartEnum](#dappersmartenum)
3232
* [Case Insensitive String Enum](#case-insensitive-string-enum)
@@ -79,6 +79,7 @@ To install support for serialization, AutoFixture, EF Core, Model Binding, or Da
7979
```
8080
Install-Package Ardalis.SmartEnum.AutoFixture
8181
Install-Package Ardalis.SmartEnum.JsonNet
82+
Install-Package Ardalis.SmartEnum.SystemTextJson
8283
Install-Package Ardalis.SmartEnum.Utf8Json
8384
Install-Package Ardalis.SmartEnum.MessagePack
8485
Install-Package Ardalis.SmartEnum.ProtoBufNet
@@ -89,13 +90,7 @@ Install-Package Ardalis.SmartEnum.Dapper
8990

9091
## Version
9192

92-
The latest version of the package supports .NET 7. If you don't need or aren't yet ready to move to .NET 7 or later, you should install the previous stable version, [Ardalis.SmartEnum 2.1](https://www.nuget.org/packages/Ardalis.SmartEnum/2.1.0).
93-
94-
Example package manager command:
95-
96-
```
97-
Install-Package Ardalis.SmartEnum -Version 2.1.0
98-
```
93+
The latest version of the package supports .NET 8 and NetStandard 2.0.
9994

10095
## Usage
10196

@@ -210,7 +205,7 @@ public class Manager
210205
{
211206
if (!ManagerType.TryFromName(value, true, out var parsed))
212207
{
213-
throw new Exception($"Invalid manage type of '{value}'");
208+
throw new Exception($"Invalid manager type of '{value}'");
214209
}
215210
_managerType = parsed;
216211
}
@@ -397,7 +392,7 @@ testEnumVar
397392
.Default( ... );
398393
```
399394

400-
N.B. For performance critical code the fluent interface carries some overhead that you may wish to avoid. See the available [benchmarks](src/SmartEnum.Benchmarks) code for your use case.
395+
N.B. For performance critical code the fluent interface carries some overhead that you may wish to avoid. See the available [benchmarks](benchmarks/SmartEnum.Benchmarks) code for your use case.
401396

402397
### SmartFlagEnum
403398

@@ -714,9 +709,15 @@ var fixture = new Fixture()
714709
var smartEnum = fixture.Create<TestEnum>();
715710
```
716711

717-
## Json<span></span>.NET support
712+
## Json support
713+
714+
When serializing a `SmartEnum` to JSON, only one of the properties (`Value` or `Name`) should be used.
715+
716+
### Json<span></span>.Net
717+
[Json.NET](https://www.newtonsoft.com/json) by default doesn't know how to do this. The `Ardalis.SmartEnum.JsonNet` package includes a couple of converters to achieve this. Simply use the attribute [JsonConverterAttribute](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverter.htm) to assign one of the converters to the `SmartEnum` to be de/serialized:
718718

719-
When serializing a `SmartEnum` to JSON, only one of the properties (`Value` or `Name`) should be used. [Json.NET](https://www.newtonsoft.com/json) by default doesn't know how to do this. The `Ardalis.SmartEnum.JsonNet` package includes a couple of converters to achieve this. Simply use the attribute [JsonConverterAttribute](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverter.htm) to assign one of the converters to the `SmartEnum` to be de/serialized:
719+
### System<span></span>.Text<span></span>.Json
720+
[System.Text.Json](https://learn.microsoft.com/en-us/dotnet/api/system.text.json?view=net-8.0) by default doesn't know how to do this. The `Ardalis.SmartEnum.SystemTextJson` package includes a couple of converters to achieve this. Simply use the attribute [JsonConverterAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverterattribute?view=net-8.0) to assign one of the converters to the `SmartEnum` to be de/serialized:
720721

721722
```csharp
722723
public class TestClass

SmartEnum.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmartEnum.Dapper.UnitTests"
6868
EndProject
6969
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmartEnum.Dapper.IntegrationTests", "test\SmartEnum.Dapper.IntegrationTests\SmartEnum.Dapper.IntegrationTests.csproj", "{ACCA93E9-EE80-490C-81A3-824086E4EA2F}"
7070
EndProject
71+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SmartEnum.GuardClauses", "src\SmartEnum.GuardClauses\SmartEnum.GuardClauses.csproj", "{A720F348-2176-4A47-ADC5-CC2664FDA516}"
72+
EndProject
73+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartEnum.GuardClauses.UnitTests", "test\SmartEnum.GuardClauses.UnitTests\SmartEnum.GuardClauses.UnitTests.csproj", "{B7B944B3-E9DC-4CFC-BADC-11EC2F226AA2}"
74+
EndProject
7175
Global
7276
GlobalSection(SolutionConfigurationPlatforms) = preSolution
7377
Debug|Any CPU = Debug|Any CPU
@@ -162,6 +166,14 @@ Global
162166
{ACCA93E9-EE80-490C-81A3-824086E4EA2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
163167
{ACCA93E9-EE80-490C-81A3-824086E4EA2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
164168
{ACCA93E9-EE80-490C-81A3-824086E4EA2F}.Release|Any CPU.Build.0 = Release|Any CPU
169+
{A720F348-2176-4A47-ADC5-CC2664FDA516}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
170+
{A720F348-2176-4A47-ADC5-CC2664FDA516}.Debug|Any CPU.Build.0 = Debug|Any CPU
171+
{A720F348-2176-4A47-ADC5-CC2664FDA516}.Release|Any CPU.ActiveCfg = Release|Any CPU
172+
{A720F348-2176-4A47-ADC5-CC2664FDA516}.Release|Any CPU.Build.0 = Release|Any CPU
173+
{B7B944B3-E9DC-4CFC-BADC-11EC2F226AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
174+
{B7B944B3-E9DC-4CFC-BADC-11EC2F226AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
175+
{B7B944B3-E9DC-4CFC-BADC-11EC2F226AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
176+
{B7B944B3-E9DC-4CFC-BADC-11EC2F226AA2}.Release|Any CPU.Build.0 = Release|Any CPU
165177
EndGlobalSection
166178
GlobalSection(SolutionProperties) = preSolution
167179
HideSolutionNode = FALSE
@@ -190,6 +202,8 @@ Global
190202
{7E08FCFA-2318-4D36-BAB5-8AFA41F00CC3} = {FA199ECB-5F29-442A-AAC6-91DBCB7A5A04}
191203
{ADBD5097-87A4-492B-9399-6A4CCC53CD5A} = {79268877-BBEF-4DE2-B8D9-697F21933159}
192204
{ACCA93E9-EE80-490C-81A3-824086E4EA2F} = {EF5634F4-4667-4481-934C-D1CFA042AD0B}
205+
{A720F348-2176-4A47-ADC5-CC2664FDA516} = {FA199ECB-5F29-442A-AAC6-91DBCB7A5A04}
206+
{B7B944B3-E9DC-4CFC-BADC-11EC2F226AA2} = {79268877-BBEF-4DE2-B8D9-697F21933159}
193207
EndGlobalSection
194208
GlobalSection(ExtensibilityGlobals) = postSolution
195209
SolutionGuid = {46896DE3-41B8-442F-A6FB-6AC9F11CCBCE}

benchmarks/SmartEnum.Benchmarks/FromNameBenchmarks.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,27 @@ public class FromNameBenchmarks
1212
////////////////////////////////////////////////////////////////////////////////
1313
// Enum
1414

15+
private static TestEnum ParseTestEnum(string value, bool ignoreCase = false)
16+
{
17+
#if NETSTANDARD2_0
18+
return (TestEnum)Enum.Parse(typeof(TestEnum), value, ignoreCase);
19+
#else
20+
return Enum.Parse<TestEnum>(value, ignoreCase);
21+
#endif
22+
}
23+
1524
[Benchmark]
16-
public TestEnum Enum_FromName_One() => Enum.Parse<TestEnum>("One");
25+
public TestEnum Enum_FromName_One() => ParseTestEnum("One");
1726

1827
[Benchmark]
19-
public TestEnum Enum_FromName_Ten() => Enum.Parse<TestEnum>("Ten");
28+
public TestEnum Enum_FromName_Ten() => ParseTestEnum("Ten");
2029

2130
[Benchmark]
2231
public TestEnum Enum_FromName_Invalid()
2332
{
2433
try
2534
{
26-
return Enum.Parse<TestEnum>("Invalid");
35+
return ParseTestEnum("Invalid");
2736
}
2837
catch (Exception)
2938
{
@@ -32,18 +41,18 @@ public TestEnum Enum_FromName_Invalid()
3241
}
3342

3443
[Benchmark]
35-
public TestEnum Enum_FromName_one_IgnoreCase() => Enum.Parse<TestEnum>("one", true);
44+
public TestEnum Enum_FromName_one_IgnoreCase() => ParseTestEnum("one", true);
3645

3746
[Benchmark]
38-
public TestEnum Enum_FromName_ten_IgnoreCase() => Enum.Parse<TestEnum>("ten", true);
47+
public TestEnum Enum_FromName_ten_IgnoreCase() => ParseTestEnum("ten", true);
3948

4049

4150
[Benchmark]
4251
public TestEnum Enum_FromName_Invalid_IgnoreCase()
4352
{
4453
try
4554
{
46-
return Enum.Parse<TestEnum>("Invalid", true);
55+
return ParseTestEnum("Invalid", true);
4756
}
4857
catch (Exception)
4958
{
@@ -229,4 +238,4 @@ public TestSmartEnum SmartEnum_TryFromName_Invalid_IgnoreCase()
229238
}
230239

231240
}
232-
}
241+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using Ardalis.GuardClauses;
2+
using System;
3+
4+
namespace Ardalis.SmartEnum.GuardClauses
5+
{
6+
/// <summary>
7+
/// Provides guard clauses to ensure input values are valid instances of a specified SmartEnum.
8+
/// </summary>
9+
public static class GuardAgainstSmartEnumOutOfRange
10+
{
11+
/// <summary>
12+
/// Throws a<see cref="SmartEnumNotFoundException" /> or a custom<see cref="Exception" />
13+
/// if <paramref name="input"/> is not a valid <see cref="SmartEnum{TEnum}"/> value.
14+
/// </summary>
15+
/// <typeparam name="TEnum">The type of the smart enum.</typeparam>
16+
/// <param name="guardClause">The guard clause interface.</param>
17+
/// <param name="input">The value to check against the smart enum values.</param>
18+
/// <param name="message">Optional. Custom error message to pass to <see cref="SmartEnumNotFoundException"/>.</param>
19+
/// <param name="exceptionCreator">Optional. A function that creates a custom exception.</param>
20+
/// <returns>The valid <see cref="SmartEnum{TEnum}"/> value <paramref name="input" />.</returns>
21+
/// <exception cref="SmartEnumNotFoundException">Thrown when <paramref name="input" />
22+
/// is not a valid enum value, and no custom exception is provided.</exception>
23+
/// <exception cref="Exception">Thrown when a custom exception is provided by <paramref name="exceptionCreator" />.</exception>
24+
public static TEnum SmartEnumOutOfRange<TEnum>(
25+
this IGuardClause guardClause,
26+
int input,
27+
string message = null,
28+
Func<Exception> exceptionCreator = null)
29+
where TEnum : SmartEnum<TEnum>
30+
{
31+
return guardClause.SmartEnumOutOfRange<TEnum, int>(input, message, exceptionCreator);
32+
}
33+
34+
/// <summary>
35+
/// Throws a <see cref="SmartEnumNotFoundException"/> or a custom <see cref="Exception"/>
36+
/// if <paramref name="input"/> is not a valid <see cref="SmartEnum{TEnum, TValue}"/> value.
37+
/// </summary>
38+
/// <typeparam name="TEnum">The type of the smart enum.</typeparam>
39+
/// <typeparam name="TValue">The type of the value that the smart enum uses.</typeparam>
40+
/// <param name="guardClause">The guard clause interface.</param>
41+
/// <param name="input">The value to check against the smart enum values.</param>
42+
/// <param name="message">Optional. Custom error message to pass to <see cref="SmartEnumNotFoundException"/>.</param>
43+
/// <param name="exceptionCreator">Optional. A function that creates a custom exception.</param>
44+
/// <returns>The valid enum value <typeparamref name="TEnum"/> corresponding to <paramref name="input"/>.</returns>
45+
/// <exception cref="SmartEnumNotFoundException">Thrown when <paramref name="input"/>
46+
/// is not a valid enum value and no custom exception is provided.</exception>
47+
/// <exception cref="Exception">Thrown when a custom exception
48+
/// is provided by <paramref name="exceptionCreator"/>.</exception>
49+
public static TEnum SmartEnumOutOfRange<TEnum, TValue>(
50+
this IGuardClause guardClause,
51+
TValue input,
52+
string message = null,
53+
Func<Exception> exceptionCreator = null)
54+
where TEnum : SmartEnum<TEnum, TValue>
55+
where TValue : IEquatable<TValue>, IComparable<TValue>
56+
{
57+
if (SmartEnum<TEnum, TValue>.TryFromValue(input, out TEnum result))
58+
{
59+
return result;
60+
}
61+
62+
var exceptionMessage = message ?? $"The value '{input}' is not a valid {typeof(TEnum).Name}.";
63+
throw exceptionCreator?.Invoke() ?? new SmartEnumNotFoundException(exceptionMessage);
64+
}
65+
}
66+
}

0 commit comments

Comments
 (0)