Skip to content

Commit b149a5e

Browse files
committed
refactor: Improved code quality based on roslyn suggestions
1 parent 8811044 commit b149a5e

20 files changed

Lines changed: 186 additions & 242 deletions

.editorconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ dotnet_naming_style.begins_with_i.capitalization = pascal_case
186186
# Disabled rules
187187

188188
dotnet_diagnostic.CA1720.severity = none
189+
dotnet_diagnostic.CA1303.severity = none
190+
dotnet_diagnostic.S3358.severity = none
189191

190192
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
191193
indent_size = 2

Directory.Packages.props

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<Project>
2-
<PropertyGroup>
3-
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4-
</PropertyGroup>
5-
<ItemGroup>
6-
<PackageVersion Include="Avalonia" Version="11.3.12" />
7-
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="9.0.14" />
8-
<PackageVersion Include="Microsoft.Maui.Controls" Version="9.0.120" />
9-
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.21.0.135717" />
10-
</ItemGroup>
11-
</Project>
2+
<PropertyGroup>
3+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<PackageVersion Include="Avalonia" Version="11.3.12" />
7+
<PackageVersion Include="Microsoft.AspNetCore.Components.Web" Version="9.0.14" />
8+
<PackageVersion Include="Microsoft.Maui.Controls" Version="9.0.120" />
9+
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.21.0.135717" />
10+
</ItemGroup>
11+
</Project>

src/TypeGuard.Console/ConsoleInput.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class ConsoleInput : IInputProvider
1818
/// <param name="cancellationToken">A token to cancel the asynchronous operation.</param>
1919
/// <returns>A task representing the asynchronous operation. The task result contains the trimmed input string, or null if no input was provided.</returns>
2020
public async Task<string?> GetInputAsync(CancellationToken cancellationToken = default) =>
21-
await Task.Run(GetInput, cancellationToken);
21+
await Task.Run(GetInput, cancellationToken).ConfigureAwait(false);
2222

2323
/// <summary>
2424
/// Synchronously reads a line of text from the console, trimming any leading or trailing whitespace.

src/TypeGuard.Console/ConsoleOutput.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class ConsoleOutput : IOutputProvider
2121
public async Task DisplayPromptAsync(
2222
string message,
2323
CancellationToken cancellationToken = default
24-
) => await Task.Run(() => DisplayPrompt(message), cancellationToken);
24+
) => await Task.Run(() => DisplayPrompt(message), cancellationToken).ConfigureAwait(false);
2525

2626
/// <summary>
2727
/// Asynchronously displays an error message to the console in red and waits for the user to
@@ -37,7 +37,7 @@ public async Task DisplayPromptAsync(
3737
public async Task DisplayErrorAsync(
3838
string message,
3939
CancellationToken cancellationToken = default
40-
) => await Task.Run(() => DisplayError(message), cancellationToken);
40+
) => await Task.Run(() => DisplayError(message), cancellationToken).ConfigureAwait(false);
4141

4242
/// <summary>
4343
/// Synchronously displays a prompt message to the console, followed by a colon and space.

src/TypeGuard.Core/Builders/BuilderBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ protected TSelf AddRule(IValidatorRule<T> rule)
5555
public async Task<T> GetAsync(CancellationToken cancellationToken = default)
5656
{
5757
_frozen = true;
58-
return await _handler.GetValidInputAsync(cancellationToken);
58+
return await _handler.GetValidInputAsync(cancellationToken).ConfigureAwait(false);
5959
}
6060

6161
/// <summary>

src/TypeGuard.Core/Builders/StringInputBuilder.cs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,36 +44,25 @@ public StringInputBuilder WithLengthRange(
4444
int? minLength = null,
4545
int? maxLength = null,
4646
string? customMessage = null
47-
)
48-
{
49-
if (minLength is < 0)
50-
{
51-
throw new ArgumentOutOfRangeException(
47+
) =>
48+
minLength is < 0
49+
? throw new ArgumentOutOfRangeException(
5250
nameof(minLength),
5351
minLength,
5452
"minLength must be greater than or equal to zero."
55-
);
56-
}
57-
58-
if (maxLength is < 0)
59-
{
60-
throw new ArgumentOutOfRangeException(
53+
)
54+
: maxLength is < 0
55+
? throw new ArgumentOutOfRangeException(
6156
nameof(maxLength),
6257
maxLength,
6358
"maxLength must be greater than or equal to zero."
64-
);
65-
}
66-
67-
if (minLength.HasValue && maxLength.HasValue && minLength.Value > maxLength.Value)
68-
{
69-
throw new ArgumentException(
59+
)
60+
: minLength.HasValue && maxLength.HasValue && minLength.Value > maxLength.Value
61+
? throw new ArgumentException(
7062
$"minLength ({minLength}) must be less than or equal to maxLength ({maxLength}).",
7163
nameof(minLength)
72-
);
73-
}
74-
75-
return AddRule(new StringLengthRule(minLength, maxLength, customMessage));
76-
}
64+
)
65+
: AddRule(new StringLengthRule(minLength, maxLength, customMessage));
7766

7867
/// <summary>
7968
/// Adds a rule that ensures the string contains numeric digits.

src/TypeGuard.Core/Handlers/GuidHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ protected override bool TryParse(string? input, out Guid value, out string? erro
2424
return true;
2525
}
2626

27-
value = default;
27+
value = Guid.Empty;
2828
errorMessage = "Please enter a valid GUID (e.g., 3f2504e0-4f89-11d3-9a0c-0305e82c3301).";
2929
return false;
3030
}

src/TypeGuard.Core/Handlers/HandlerBase.cs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,32 @@ public async Task<T> GetValidInputAsync(CancellationToken cancellationToken = de
4242
{
4343
cancellationToken.ThrowIfCancellationRequested();
4444

45-
await _outputProvider.DisplayPromptAsync(_prompt, cancellationToken);
46-
string? rawInput = await _inputProvider.GetInputAsync(cancellationToken);
45+
await _outputProvider
46+
.DisplayPromptAsync(_prompt, cancellationToken)
47+
.ConfigureAwait(false);
48+
string? rawInput = await _inputProvider
49+
.GetInputAsync(cancellationToken)
50+
.ConfigureAwait(false);
4751

4852
if (!TryParse(rawInput, out T? value, out string? parseError))
4953
{
50-
await _outputProvider.DisplayErrorAsync(parseError!, cancellationToken);
54+
await _outputProvider
55+
.DisplayErrorAsync(parseError!, cancellationToken)
56+
.ConfigureAwait(false);
5157
continue;
5258
}
5359

54-
bool allRulesPassed = true;
55-
foreach (IValidatorRule<T> rule in _rules.Where(rule => !rule.IsValid(value!)))
56-
{
57-
await _outputProvider.DisplayErrorAsync(rule.ErrorMessage, cancellationToken);
58-
allRulesPassed = false;
59-
break;
60-
}
60+
IValidatorRule<T>? failedRule = _rules.FirstOrDefault(rule => !rule.IsValid(value!));
6161

62-
if (allRulesPassed)
62+
if (failedRule is not null)
6363
{
64-
return value!;
64+
await _outputProvider
65+
.DisplayErrorAsync(failedRule.ErrorMessage, cancellationToken)
66+
.ConfigureAwait(false);
67+
continue;
6568
}
69+
70+
return value!;
6671
}
6772
}
6873

src/TypeGuard.Core/Handlers/TimeSpanHandler.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
using TypeGuard.Core.Interfaces;
1+
using System.Globalization;
22

33
namespace TypeGuard.Core.Handlers;
44

5+
using Interfaces;
6+
57
/// <summary>
68
/// An input handler that prompts for and validates TimeSpan input.
79
/// Accepts various formats including "hh:mm:ss", "d.hh:mm:ss", or total units like "5.5".
@@ -22,16 +24,16 @@ public class TimeSpanHandler(
2224
protected override bool TryParse(string? input, out TimeSpan value, out string? errorMessage)
2325
{
2426
bool success = format is not null
25-
? TimeSpan.TryParseExact(input, format, null, out value)
26-
: TimeSpan.TryParse(input, out value);
27+
? TimeSpan.TryParseExact(input, format, CultureInfo.InvariantCulture, out value)
28+
: TimeSpan.TryParse(input, CultureInfo.InvariantCulture, out value);
2729

2830
if (success)
2931
{
3032
errorMessage = null;
3133
return true;
3234
}
3335

34-
value = default;
36+
value = TimeSpan.Zero;
3537
errorMessage = format is not null
3638
? $"Please enter a valid time span in the format '{format}'."
3739
: "Please enter a valid time span (e.g., '1:30:00' or '1.12:00:00').";
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Runtime.CompilerServices;
2+
3+
namespace TypeGuard.Core.Rules;
4+
5+
internal static class BuildHelper<T>
6+
{
7+
internal static HashSet<T> BuildSet(
8+
IEnumerable<T> values,
9+
[CallerArgumentExpression(nameof(values))] string? paramName = null
10+
)
11+
{
12+
ArgumentNullException.ThrowIfNull(values, paramName);
13+
HashSet<T> set = [.. values];
14+
return set.Count == 0 ? throw new ArgumentException("Cannot be empty.", paramName) : set;
15+
}
16+
}

0 commit comments

Comments
 (0)