From 0b96fb6b472300c655c3d42ea9d4a46d9aec946c Mon Sep 17 00:00:00 2001 From: Dixin Date: Sat, 27 Jan 2024 02:21:36 -0800 Subject: [PATCH] Upgrade to C# 12. --- .../RetryManagerOptions.cs | 2 - .../RetryStrategyOptions.cs | 81 +++---------------- .../AsyncExecution.cs | 8 +- .../AsyncExecution`1.cs | 44 +++------- .../ErrorDetectionStrategy.cs | 15 ++-- .../ExceptionDetection.cs | 15 ++-- .../ExponentialBackoff.cs | 37 ++++----- .../FixedInterval.cs | 27 +++---- .../Incremental.cs | 31 +++---- .../{ => Properties}/IsExternalInit.cs | 0 .../Properties/NullableAttributes.cs | 58 +++++++------ .../Retry.Incremental.cs | 2 +- .../RetryPolicy.cs | 21 ++--- .../RetryingEventArgs.cs | 27 +++---- .../TestObjects/SqlExceptionCreator.cs | 13 ++- .../TestObjects/TestAsyncOperation.cs | 6 +- .../TestObjects/TestRetryStrategy.cs | 8 +- .../Counter.cs | 4 +- .../FakeSqlExceptionGenerator.cs | 11 ++- .../StrategyTests.cs | 2 +- .../TestSupport/TestAsyncOperation.cs | 6 +- .../TestSupport/TestRetryStrategy.cs | 8 +- TransientFaultHandling.Core.sln.DotSettings | 2 + 23 files changed, 143 insertions(+), 285 deletions(-) rename Source/TransientFaultHandling.Core/{ => Properties}/IsExternalInit.cs (100%) diff --git a/Source/TransientFaultHandling.Configuration.Core/RetryManagerOptions.cs b/Source/TransientFaultHandling.Configuration.Core/RetryManagerOptions.cs index 9bca238..c2f123f 100644 --- a/Source/TransientFaultHandling.Configuration.Core/RetryManagerOptions.cs +++ b/Source/TransientFaultHandling.Configuration.Core/RetryManagerOptions.cs @@ -4,7 +4,6 @@ /// Represents the options for . /// public record RetryManagerOptions( -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member string? DefaultRetryStrategy, string? DefaultSqlConnectionRetryStrategy, string? DefaultSqlCommandRetryStrategy, @@ -12,7 +11,6 @@ public record RetryManagerOptions( string? DefaultAzureCachingRetryStrategy, string? DefaultAzureStorageRetryStrategy, IConfigurationSection? RetryStrategy) -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member { /// /// Initializes a new instance of the record. diff --git a/Source/TransientFaultHandling.Configuration.Core/RetryStrategyOptions.cs b/Source/TransientFaultHandling.Configuration.Core/RetryStrategyOptions.cs index b31b74c..c0e1aa2 100644 --- a/Source/TransientFaultHandling.Configuration.Core/RetryStrategyOptions.cs +++ b/Source/TransientFaultHandling.Configuration.Core/RetryStrategyOptions.cs @@ -3,43 +3,29 @@ /// /// Represents the options for . /// -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public abstract record RetryStrategyOptions(bool FastFirstRetry); -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Represents the options for retry strategy. /// public record FixedIntervalOptions(bool FastFirstRetry, int RetryCount, TimeSpan RetryInterval) : RetryStrategyOptions(FastFirstRetry) { - private readonly int retryCount; - - private readonly TimeSpan retryInterval; - /// /// Initializes a new instance of the record. /// - public FixedIntervalOptions() : this(true, default, default) + public FixedIntervalOptions() : this(RetryStrategy.DefaultFirstFastRetry, default, default) { } /// /// Gets or sets the retry count. /// - public int RetryCount - { - get => this.retryCount; - init => this.retryCount = value.ThrowIfNegative(); - } + public int RetryCount { get; init; } = RetryCount.ThrowIfNegative(); /// /// Gets the time interval between retries. /// - public TimeSpan RetryInterval - { - get => this.retryInterval; - init => this.retryInterval = value.ThrowIfNegative(); - } + public TimeSpan RetryInterval { get; init; } = RetryInterval.ThrowIfNegative(); } /// @@ -47,45 +33,27 @@ public TimeSpan RetryInterval /// public record IncrementalOptions(bool FastFirstRetry, int RetryCount, TimeSpan InitialInterval, TimeSpan Increment) : RetryStrategyOptions(FastFirstRetry) { - private readonly int retryCount; - - private readonly TimeSpan initialInterval; - - private readonly TimeSpan increment; - /// /// Initializes a new instance of the record. /// - public IncrementalOptions() : this(true, default, default, default) + public IncrementalOptions() : this(RetryStrategy.DefaultFirstFastRetry, default, default, default) { } /// /// Gets the maximum number of retry attempts. /// - public int RetryCount - { - get => this.retryCount; - init => this.retryCount = value.ThrowIfNegative(); - } + public int RetryCount { get; init; } = RetryCount.ThrowIfNegative(); /// /// Gets the initial interval that will apply for the first retry. /// - public TimeSpan InitialInterval - { - get => this.initialInterval; - init => this.initialInterval = value.ThrowIfNegative(); - } + public TimeSpan InitialInterval { get; init; } = InitialInterval.ThrowIfNegative(); /// /// Gets the incremental time value that will be used to calculate the progressive delay between retries.. /// - public TimeSpan Increment - { - get => this.increment; - init => this.increment = value.ThrowIfNegative(); - } + public TimeSpan Increment { get; init; } = Increment.ThrowIfNegative(); } /// @@ -93,55 +61,30 @@ public TimeSpan Increment /// public record ExponentialBackoffOptions(bool FastFirstRetry, int RetryCount, TimeSpan MinBackOff, TimeSpan MaxBackOff, TimeSpan DeltaBackOff) : RetryStrategyOptions(FastFirstRetry) { - - private readonly int retryCount; - - private readonly TimeSpan minBackOff; - - private readonly TimeSpan maxBackOff; - - private readonly TimeSpan deltaBackOff; - /// /// Initializes a new instance of the record. /// - public ExponentialBackoffOptions() : this(true, default, default, default, default) + public ExponentialBackoffOptions() : this(RetryStrategy.DefaultFirstFastRetry, default, default, default, default) { } /// /// Gets the maximum number of retry attempts. /// - public int RetryCount - { - get => this.retryCount; - init => this.retryCount = value.ThrowIfNegative(); - } + public int RetryCount { get; init; } = RetryCount.ThrowIfNegative(); /// /// Gets the minimum backoff time. /// - public TimeSpan MinBackOff - { - get => this.minBackOff; - init => this.minBackOff = value.ThrowIfNegative(); - } + public TimeSpan MinBackOff { get; init; } = MinBackOff.ThrowIfNegative(); /// /// Gets the maximum backoff time. /// - public TimeSpan MaxBackOff - { - get => this.maxBackOff; - init => this.maxBackOff = value.ThrowIfNegative(); - } + public TimeSpan MaxBackOff { get; init; } = MaxBackOff.ThrowIfNegative(); /// /// Gets the value that will be used to calculate a random delta in the exponential delay between retries. /// - public TimeSpan DeltaBackOff - { - get => this.deltaBackOff; - init => this.deltaBackOff = value.ThrowIfNegative(); - } + public TimeSpan DeltaBackOff { get; init; } = DeltaBackOff.ThrowIfNegative(); } \ No newline at end of file diff --git a/Source/TransientFaultHandling.Core/AsyncExecution.cs b/Source/TransientFaultHandling.Core/AsyncExecution.cs index 24be534..1d75a53 100644 --- a/Source/TransientFaultHandling.Core/AsyncExecution.cs +++ b/Source/TransientFaultHandling.Core/AsyncExecution.cs @@ -4,15 +4,11 @@ /// Provides a wrapper for a non-generic and calls into the pipeline /// to retry only the generic version of the . /// -internal class AsyncExecution : AsyncExecution +internal class AsyncExecution(Func taskAction, ShouldRetry shouldRetry, Func isTransient, Action onRetrying, bool fastFirstRetry, CancellationToken cancellationToken) + : AsyncExecution(() => StartAsGenericTask(taskAction), shouldRetry, isTransient, onRetrying, fastFirstRetry, cancellationToken) { private static Task? cachedBoolTask; - public AsyncExecution(Func taskAction, ShouldRetry shouldRetry, Func isTransient, Action onRetrying, bool fastFirstRetry, CancellationToken cancellationToken) : - base(() => StartAsGenericTask(taskAction), shouldRetry, isTransient, onRetrying, fastFirstRetry, cancellationToken) - { - } - /// /// Wraps the non-generic into a generic . /// diff --git a/Source/TransientFaultHandling.Core/AsyncExecution`1.cs b/Source/TransientFaultHandling.Core/AsyncExecution`1.cs index 9c23834..af98555 100644 --- a/Source/TransientFaultHandling.Core/AsyncExecution`1.cs +++ b/Source/TransientFaultHandling.Core/AsyncExecution`1.cs @@ -4,39 +4,17 @@ /// Handles the execution and retries of the user-initiated task. /// /// The result type of the user-initiated task. -internal class AsyncExecution +internal class AsyncExecution(Func> taskFunc, ShouldRetry shouldRetry, Func isTransient, Action onRetrying, bool fastFirstRetry, CancellationToken cancellationToken) { - private readonly Func> taskFunc; - - private readonly ShouldRetry shouldRetry; - - private readonly Func isTransient; - - private readonly Action onRetrying; - - private readonly bool fastFirstRetry; - - private readonly CancellationToken cancellationToken; - private Task? previousTask; private int retryCount; - public AsyncExecution(Func> taskFunc, ShouldRetry shouldRetry, Func isTransient, Action onRetrying, bool fastFirstRetry, CancellationToken cancellationToken) - { - this.taskFunc = taskFunc; - this.shouldRetry = shouldRetry; - this.isTransient = isTransient; - this.onRetrying = onRetrying; - this.fastFirstRetry = fastFirstRetry; - this.cancellationToken = cancellationToken; - } - internal Task ExecuteAsync() => this.ExecuteAsyncImpl(null); private Task ExecuteAsyncImpl(Task? ignore) { - if (this.cancellationToken.IsCancellationRequested) + if (cancellationToken.IsCancellationRequested) { if (this.previousTask is not null) { @@ -51,11 +29,11 @@ private Task ExecuteAsyncImpl(Task? ignore) Task task; try { - task = this.taskFunc(); + task = taskFunc(); } catch (Exception ex) { - if (!this.isTransient(ex)) + if (!isTransient(ex)) { throw; } @@ -68,14 +46,14 @@ private Task ExecuteAsyncImpl(Task? ignore) if (task is null) { throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, Resources.TaskCannotBeNull, nameof(this.taskFunc)), nameof(this.taskFunc)); + string.Format(CultureInfo.InvariantCulture, Resources.TaskCannotBeNull, nameof(taskFunc)), nameof(taskFunc)); } return task.Status switch { TaskStatus.RanToCompletion => task, TaskStatus.Created => throw new ArgumentException( - string.Format(CultureInfo.InvariantCulture, Resources.TaskMustBeScheduled, nameof(this.taskFunc)), nameof(this.taskFunc)), + string.Format(CultureInfo.InvariantCulture, Resources.TaskMustBeScheduled, nameof(taskFunc)), nameof(taskFunc)), _ => task .ContinueWith(this.ExecuteAsyncContinueWith, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default) .Unwrap() @@ -84,7 +62,7 @@ private Task ExecuteAsyncImpl(Task? ignore) private Task ExecuteAsyncContinueWith(Task runningTask) { - if (!runningTask.IsFaulted || this.cancellationToken.IsCancellationRequested) + if (!runningTask.IsFaulted || cancellationToken.IsCancellationRequested) { return runningTask; } @@ -107,7 +85,7 @@ private Task ExecuteAsyncContinueWith(Task runningTask) return taskCompletionSource.Task; } - if (!this.isTransient(innerException) || !this.shouldRetry(this.retryCount++, innerException, out TimeSpan zero)) + if (!isTransient(innerException) || !shouldRetry(this.retryCount++, innerException, out TimeSpan zero)) { return runningTask; } @@ -117,12 +95,12 @@ private Task ExecuteAsyncContinueWith(Task runningTask) zero = TimeSpan.Zero; } - this.onRetrying(this.retryCount, innerException, zero); + onRetrying(this.retryCount, innerException, zero); this.previousTask = runningTask; - if (zero > TimeSpan.Zero && (this.retryCount > 1 || !this.fastFirstRetry)) + if (zero > TimeSpan.Zero && (this.retryCount > 1 || !fastFirstRetry)) { return Task - .Delay(zero, this.cancellationToken) + .Delay(zero, cancellationToken) .ContinueWith(this.ExecuteAsyncImpl, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default) .Unwrap(); } diff --git a/Source/TransientFaultHandling.Core/ErrorDetectionStrategy.cs b/Source/TransientFaultHandling.Core/ErrorDetectionStrategy.cs index fe8c4d1..2111c26 100644 --- a/Source/TransientFaultHandling.Core/ErrorDetectionStrategy.cs +++ b/Source/TransientFaultHandling.Core/ErrorDetectionStrategy.cs @@ -3,16 +3,13 @@ /// /// Detects specific transient conditions. /// -public class ErrorDetectionStrategy : ITransientErrorDetectionStrategy +/// +/// Initializes a new instance of the class. +/// +/// The predicate function to detect whether the specified exception is transient. The default behavior is to catch all exceptions and retry. +public class ErrorDetectionStrategy(Func? isTransient = null) : ITransientErrorDetectionStrategy { - private readonly Func isTransient; - - /// - /// Initializes a new instance of the class. - /// - /// The predicate function to detect whether the specified exception is transient. The default behavior is to catch all exceptions and retry. - public ErrorDetectionStrategy(Func? isTransient = null) => - this.isTransient = isTransient ?? (_ => true); + private readonly Func isTransient = isTransient ?? (_ => true); /// /// Gets an instance of that catches all exceptions as transient. diff --git a/Source/TransientFaultHandling.Core/ExceptionDetection.cs b/Source/TransientFaultHandling.Core/ExceptionDetection.cs index 03844b4..88d0636 100644 --- a/Source/TransientFaultHandling.Core/ExceptionDetection.cs +++ b/Source/TransientFaultHandling.Core/ExceptionDetection.cs @@ -3,18 +3,15 @@ /// /// Detects specific transient conditions. /// +/// +/// Initializes a new instance of the class. +/// +/// The predicate function to detect whether the specified exception is transient. [Obsolete("Use Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.ErrorDetectionStrategy.")] -public class ExceptionDetection : ITransientErrorDetectionStrategy +public class ExceptionDetection(Func? isTransient = null) : ITransientErrorDetectionStrategy { - private readonly Func isTransient; + private readonly Func isTransient = isTransient ?? (_ => true); - /// - /// Initializes a new instance of the class. - /// - /// The predicate function to detect whether the specified exception is transient. - public ExceptionDetection(Func? isTransient = null) => - this.isTransient = isTransient ?? (_ => true); - /// /// Determines whether the specified exception is transient. /// diff --git a/Source/TransientFaultHandling.Core/ExponentialBackoff.cs b/Source/TransientFaultHandling.Core/ExponentialBackoff.cs index 0ee26a1..175e7a0 100644 --- a/Source/TransientFaultHandling.Core/ExponentialBackoff.cs +++ b/Source/TransientFaultHandling.Core/ExponentialBackoff.cs @@ -3,15 +3,24 @@ /// /// A retry strategy with backoff parameters for calculating the exponential delay between retries. /// -public class ExponentialBackoff : RetryStrategy +/// +/// Initializes a new instance of the class with the specified name, retry settings, and fast retry option. +/// +/// The name of the retry strategy. +/// The maximum number of retry attempts. +/// The minimum backoff time +/// The maximum backoff time. +/// The value that will be used to calculate a random delta in the exponential delay between retries. +/// true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. +public class ExponentialBackoff(string? name, int retryCount, TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff, bool firstFastRetry) : RetryStrategy(name, firstFastRetry) { - private readonly int retryCount; + private readonly int retryCount = retryCount.ThrowIfNegative(); - private readonly TimeSpan minBackoff; + private readonly TimeSpan minBackoff = minBackoff.ThrowIfOutOfRange(TimeSpan.Zero, maxBackoff); - private readonly TimeSpan maxBackoff; + private readonly TimeSpan maxBackoff = maxBackoff.ThrowIfNegative(); - private readonly TimeSpan deltaBackoff; + private readonly TimeSpan deltaBackoff = deltaBackoff.ThrowIfNegative(); /// /// Initializes a new instance of the class. @@ -46,24 +55,6 @@ public ExponentialBackoff(string? name, int retryCount, TimeSpan minBackoff, Tim { } - /// - /// Initializes a new instance of the class with the specified name, retry settings, and fast retry option. - /// - /// The name of the retry strategy. - /// The maximum number of retry attempts. - /// The minimum backoff time - /// The maximum backoff time. - /// The value that will be used to calculate a random delta in the exponential delay between retries. - /// true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. - public ExponentialBackoff(string? name, int retryCount, TimeSpan minBackoff, TimeSpan maxBackoff, TimeSpan deltaBackoff, bool firstFastRetry) : - base(name, firstFastRetry) - { - this.retryCount = retryCount.ThrowIfNegative(); - this.minBackoff = minBackoff.ThrowIfOutOfRange(TimeSpan.Zero, maxBackoff); - this.maxBackoff = maxBackoff.ThrowIfNegative(); - this.deltaBackoff = deltaBackoff.ThrowIfNegative(); - } - /// /// Returns the corresponding ShouldRetry delegate. /// diff --git a/Source/TransientFaultHandling.Core/FixedInterval.cs b/Source/TransientFaultHandling.Core/FixedInterval.cs index 0b2f696..b97c278 100644 --- a/Source/TransientFaultHandling.Core/FixedInterval.cs +++ b/Source/TransientFaultHandling.Core/FixedInterval.cs @@ -3,11 +3,18 @@ /// /// Represents a retry strategy with a specified number of retry attempts and a default, fixed time interval between retries. /// -public class FixedInterval : RetryStrategy +/// +/// Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. +/// +/// The retry strategy name. +/// The maximum number of retry attempts. +/// The time interval between retries. +/// true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. +public class FixedInterval(string? name, int retryCount, TimeSpan retryInterval, bool firstFastRetry) : RetryStrategy(name, firstFastRetry) { - private readonly int retryCount; + private readonly int retryCount = retryCount.ThrowIfNegative(); - private readonly TimeSpan retryInterval; + private readonly TimeSpan retryInterval = retryInterval.ThrowIfNegative(); /// /// Initializes a new instance of the class. @@ -45,20 +52,6 @@ public FixedInterval(string? name, int retryCount, TimeSpan retryInterval) : { } - /// - /// Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. - /// - /// The retry strategy name. - /// The maximum number of retry attempts. - /// The time interval between retries. - /// true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. - public FixedInterval(string? name, int retryCount, TimeSpan retryInterval, bool firstFastRetry) : - base(name, firstFastRetry) - { - this.retryCount = retryCount.ThrowIfNegative(); - this.retryInterval = retryInterval.ThrowIfNegative(); - } - /// /// Returns the corresponding ShouldRetry delegate. /// diff --git a/Source/TransientFaultHandling.Core/Incremental.cs b/Source/TransientFaultHandling.Core/Incremental.cs index 3bb8c7d..f28311c 100644 --- a/Source/TransientFaultHandling.Core/Incremental.cs +++ b/Source/TransientFaultHandling.Core/Incremental.cs @@ -3,13 +3,21 @@ /// /// A retry strategy with a specified number of retry attempts and an incremental time interval between retries. /// -public class Incremental : RetryStrategy +/// +/// Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. +/// +/// The retry strategy name. +/// The number of retry attempts. +/// The initial interval that will apply for the first retry. +/// The incremental time value that will be used to calculate the progressive delay between retries. +/// true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. +public class Incremental(string? name, int retryCount, TimeSpan initialInterval, TimeSpan increment, bool firstFastRetry) : RetryStrategy(name, firstFastRetry) { - private readonly int retryCount; + private readonly int retryCount = retryCount.ThrowIfNegative(); - private readonly TimeSpan initialInterval; + private readonly TimeSpan initialInterval = initialInterval.ThrowIfNegative(); - private readonly TimeSpan increment; + private readonly TimeSpan increment = increment.ThrowIfNegative(); /// /// Initializes a new instance of the class. @@ -39,21 +47,6 @@ public Incremental(string? name, int retryCount, TimeSpan initialInterval, TimeS { } - /// - /// Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. - /// - /// The retry strategy name. - /// The number of retry attempts. - /// The initial interval that will apply for the first retry. - /// The incremental time value that will be used to calculate the progressive delay between retries. - /// true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. - public Incremental(string? name, int retryCount, TimeSpan initialInterval, TimeSpan increment, bool firstFastRetry) : base(name, firstFastRetry) - { - this.retryCount = retryCount.ThrowIfNegative(); - this.initialInterval = initialInterval.ThrowIfNegative(); - this.increment = increment.ThrowIfNegative(); - } - /// /// Returns the corresponding ShouldRetry delegate. /// diff --git a/Source/TransientFaultHandling.Core/IsExternalInit.cs b/Source/TransientFaultHandling.Core/Properties/IsExternalInit.cs similarity index 100% rename from Source/TransientFaultHandling.Core/IsExternalInit.cs rename to Source/TransientFaultHandling.Core/Properties/IsExternalInit.cs diff --git a/Source/TransientFaultHandling.Core/Properties/NullableAttributes.cs b/Source/TransientFaultHandling.Core/Properties/NullableAttributes.cs index 70a0975..a17e4a0 100644 --- a/Source/TransientFaultHandling.Core/Properties/NullableAttributes.cs +++ b/Source/TransientFaultHandling.Core/Properties/NullableAttributes.cs @@ -46,60 +46,57 @@ sealed class NotNullAttribute : Attribute { } /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. +/// Initializes the attribute with the specified return value condition. +/// +/// The return value condition. If the method returns this value, the associated parameter may be null. +/// [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if SYSTEM_PRIVATE_CORELIB public #else internal #endif - sealed class MaybeNullWhenAttribute : Attribute + sealed class MaybeNullWhenAttribute(bool returnValue) : Attribute { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter may be null. - /// - public MaybeNullWhenAttribute(bool returnValue) => this.ReturnValue = returnValue; /// Gets the return value condition. - public bool ReturnValue { get; } + public bool ReturnValue { get; } = returnValue; } /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. +/// Initializes the attribute with the specified return value condition. +/// +/// The return value condition. If the method returns this value, the associated parameter will not be null. +/// [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if SYSTEM_PRIVATE_CORELIB public #else internal #endif - sealed class NotNullWhenAttribute : Attribute + sealed class NotNullWhenAttribute(bool returnValue) : Attribute { - /// Initializes the attribute with the specified return value condition. - /// - /// The return value condition. If the method returns this value, the associated parameter will not be null. - /// - public NotNullWhenAttribute(bool returnValue) => this.ReturnValue = returnValue; /// Gets the return value condition. - public bool ReturnValue { get; } + public bool ReturnValue { get; } = returnValue; } /// Specifies that the output will be non-null if the named parameter is non-null. +/// Initializes the attribute with the associated parameter name. +/// +/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. +/// [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] #if SYSTEM_PRIVATE_CORELIB public #else internal #endif - sealed class NotNullIfNotNullAttribute : Attribute + sealed class NotNullIfNotNullAttribute(string parameterName) : Attribute { - /// Initializes the attribute with the associated parameter name. - /// - /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. - /// - public NotNullIfNotNullAttribute(string parameterName) => this.ParameterName = parameterName; /// Gets the associated parameter name. - public string ParameterName { get; } + public string ParameterName { get; } = parameterName; } /// Applied to a method that will never return under any circumstance. @@ -113,23 +110,22 @@ sealed class DoesNotReturnAttribute : Attribute { } /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. +/// Initializes the attribute with the specified parameter value. +/// +/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to +/// the associated parameter matches this value. +/// [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if SYSTEM_PRIVATE_CORELIB public #else internal #endif - sealed class DoesNotReturnIfAttribute : Attribute + sealed class DoesNotReturnIfAttribute(bool parameterValue) : Attribute { - /// Initializes the attribute with the specified parameter value. - /// - /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to - /// the associated parameter matches this value. - /// - public DoesNotReturnIfAttribute(bool parameterValue) => this.ParameterValue = parameterValue; /// Gets the condition parameter value. - public bool ParameterValue { get; } + public bool ParameterValue { get; } = parameterValue; } #endif @@ -146,7 +142,7 @@ sealed class MemberNotNullAttribute : Attribute /// /// The field or property member that is promised to be not-null. /// - public MemberNotNullAttribute(string member) => this.Members = new[] { member }; + public MemberNotNullAttribute(string member) => this.Members = [member]; /// Initializes the attribute with the list of field and property members. /// @@ -177,7 +173,7 @@ sealed class MemberNotNullWhenAttribute : Attribute public MemberNotNullWhenAttribute(bool returnValue, string member) { this.ReturnValue = returnValue; - this.Members = new[] { member }; + this.Members = [member]; } /// Initializes the attribute with the specified return value condition and list of field and property members. diff --git a/Source/TransientFaultHandling.Core/Retry.Incremental.cs b/Source/TransientFaultHandling.Core/Retry.Incremental.cs index 80f1d4c..d30dd73 100644 --- a/Source/TransientFaultHandling.Core/Retry.Incremental.cs +++ b/Source/TransientFaultHandling.Core/Retry.Incremental.cs @@ -124,7 +124,7 @@ public static Task IncrementalAsync( /// A new instance of the class. public static Incremental WithIncremental( int? retryCount = null, - TimeSpan? initialInterval =null, + TimeSpan? initialInterval = null, TimeSpan? increment = null, bool? firstFastRetry = null, string? name = null) => new( diff --git a/Source/TransientFaultHandling.Core/RetryPolicy.cs b/Source/TransientFaultHandling.Core/RetryPolicy.cs index dafe89e..f108d37 100644 --- a/Source/TransientFaultHandling.Core/RetryPolicy.cs +++ b/Source/TransientFaultHandling.Core/RetryPolicy.cs @@ -5,18 +5,13 @@ /// /// Provides the base implementation of the retry mechanism for unreliable actions and transient conditions. /// -public class RetryPolicy +/// +/// Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. +/// +/// The that is responsible for detecting transient conditions. +/// The strategy to use for this retry policy. +public class RetryPolicy(ITransientErrorDetectionStrategy errorDetectionStrategy, RetryStrategy retryStrategy) { - /// - /// Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. - /// - /// The that is responsible for detecting transient conditions. - /// The strategy to use for this retry policy. - public RetryPolicy(ITransientErrorDetectionStrategy errorDetectionStrategy, RetryStrategy retryStrategy) - { - this.ErrorDetectionStrategy= errorDetectionStrategy.ThrowIfNull(); - this.RetryStrategy = retryStrategy.ThrowIfNull(); - } /// /// Initializes a new instance of the class with the specified number of retry attempts and default fixed time interval between retries. @@ -95,12 +90,12 @@ public RetryPolicy(ITransientErrorDetectionStrategy errorDetectionStrategy, int /// /// Gets the retry strategy. /// - public RetryStrategy RetryStrategy { get; } + public RetryStrategy RetryStrategy { get; } = retryStrategy.ThrowIfNull(); /// /// Gets the instance of the error detection strategy. /// - public ITransientErrorDetectionStrategy ErrorDetectionStrategy { get; } + public ITransientErrorDetectionStrategy ErrorDetectionStrategy { get; } = errorDetectionStrategy.ThrowIfNull(); /// /// Repetitively executes the specified action while it satisfies the current retry policy. diff --git a/Source/TransientFaultHandling.Core/RetryingEventArgs.cs b/Source/TransientFaultHandling.Core/RetryingEventArgs.cs index 85c60ac..2c7806b 100644 --- a/Source/TransientFaultHandling.Core/RetryingEventArgs.cs +++ b/Source/TransientFaultHandling.Core/RetryingEventArgs.cs @@ -3,33 +3,26 @@ /// /// Contains information that is required for the event. /// -public class RetryingEventArgs : EventArgs +/// +/// Initializes a new instance of the class. +/// +/// The current retry attempt count. +/// The delay that indicates how long the current thread will be suspended before the next iteration is invoked. +/// The exception that caused the retry conditions to occur. +public class RetryingEventArgs(int currentRetryCount, TimeSpan delay, Exception lastException) : EventArgs { /// /// Gets the current retry count. /// - public int CurrentRetryCount { get; } + public int CurrentRetryCount { get; } = currentRetryCount; /// /// Gets the delay that indicates how long the current thread will be suspended before the next iteration is invoked. /// - public TimeSpan Delay { get; } + public TimeSpan Delay { get; } = delay; /// /// Gets the exception that caused the retry conditions to occur. /// - public Exception LastException { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The current retry attempt count. - /// The delay that indicates how long the current thread will be suspended before the next iteration is invoked. - /// The exception that caused the retry conditions to occur. - public RetryingEventArgs(int currentRetryCount, TimeSpan delay, Exception lastException) - { - this.CurrentRetryCount = currentRetryCount; - this.Delay = delay; - this.LastException = lastException.ThrowIfNull(); - } + public Exception LastException { get; } = lastException.ThrowIfNull(); } \ No newline at end of file diff --git a/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/SqlExceptionCreator.cs b/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/SqlExceptionCreator.cs index f91e684..335a727 100644 --- a/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/SqlExceptionCreator.cs +++ b/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/SqlExceptionCreator.cs @@ -9,19 +9,19 @@ public static SqlException CreateSqlException(string errorMessage, int errorNumb typeof(SqlErrorCollection) .GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Instance) - ?.Invoke(collection, new object[] { error }); + ?.Invoke(collection, [error]); MethodInfo createException = typeof(SqlException) .GetMethod( "CreateException", BindingFlags.NonPublic | BindingFlags.Static, null, - new Type[] { typeof(SqlErrorCollection), typeof(string) }, + [typeof(SqlErrorCollection), typeof(string)], null)!; SqlException e = (SqlException)(createException.Invoke( - null, - new object[] { collection, "7.0.0" }) ?? throw new InvalidOperationException("Failed to create SqlException.")); + null, + [collection, "7.0.0"]) ?? throw new InvalidOperationException("Failed to create SqlException.")); return e; } @@ -31,8 +31,7 @@ public static SqlError GenerateFakeSqlError(int errorNumber, string errorMessage typeof(SqlError), BindingFlags.NonPublic | BindingFlags.Instance, null, - new object?[] - { + [ errorNumber, // int infoNumber default(byte), // byte errorState default(byte), // byte errorClass @@ -41,7 +40,7 @@ public static SqlError GenerateFakeSqlError(int errorNumber, string errorMessage string.Empty, // string procedure 0, // int lineNumber null// Exception exception - }, + ], null) ?? throw new InvalidOperationException("Failed to create SqlError")); private static T Construct(params object[] p) diff --git a/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestAsyncOperation.cs b/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestAsyncOperation.cs index 1a6e3b8..b239fb2 100644 --- a/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestAsyncOperation.cs +++ b/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestAsyncOperation.cs @@ -1,6 +1,6 @@ namespace Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Bvt.Tests.TestObjects; -public class TestAsyncOperation +public class TestAsyncOperation(bool throwException = false) { public bool ThrowFatalExceptionAtBegin = false; @@ -18,9 +18,7 @@ public class TestAsyncOperation public int CountToThrowAtEnd { get; set; } - public bool ThrowException { get; set; } - - public TestAsyncOperation(bool throwException = false) => this.ThrowException = throwException; + public bool ThrowException { get; set; } = throwException; public IAsyncResult BeginMethod(AsyncCallback callback, object? state) { diff --git a/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestRetryStrategy.cs b/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestRetryStrategy.cs index b92631f..cd49bd3 100644 --- a/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestRetryStrategy.cs +++ b/Tests/TransientFaultHandling.Bvt.Tests/TestObjects/TestRetryStrategy.cs @@ -1,12 +1,8 @@ namespace Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Bvt.Tests.TestObjects; -public class TestRetryStrategy : RetryStrategy +public class TestRetryStrategy(string name, bool firstFastRetry, int customProperty) : RetryStrategy(name, firstFastRetry) { - public TestRetryStrategy(string name, bool firstFastRetry, int customProperty) - : base(name, firstFastRetry) => - this.CustomProperty = customProperty; - - public int CustomProperty { get; } + public int CustomProperty { get; } = customProperty; public int ShouldRetryCount { get; private set; } diff --git a/Tests/TransientFaultHandling.Tests.Core/Counter.cs b/Tests/TransientFaultHandling.Tests.Core/Counter.cs index c0de3e5..98f74eb 100644 --- a/Tests/TransientFaultHandling.Tests.Core/Counter.cs +++ b/Tests/TransientFaultHandling.Tests.Core/Counter.cs @@ -6,7 +6,7 @@ namespace Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Tests; internal Counter(int count) => this.count = count; - internal List Time { get; } = new(); + internal List Time { get; } = []; internal void Increase() { @@ -24,7 +24,7 @@ internal void Increase() internal Counter(int count) => this.count = count; - internal List Time { get; } = new(); + internal List Time { get; } = []; internal void Increase() { diff --git a/Tests/TransientFaultHandling.Tests.Core/FakeSqlExceptionGenerator.cs b/Tests/TransientFaultHandling.Tests.Core/FakeSqlExceptionGenerator.cs index cec3124..b69397d 100644 --- a/Tests/TransientFaultHandling.Tests.Core/FakeSqlExceptionGenerator.cs +++ b/Tests/TransientFaultHandling.Tests.Core/FakeSqlExceptionGenerator.cs @@ -22,8 +22,8 @@ public static SqlException GenerateFakeSqlException(int errorCode, string errorM return (SqlException)(Activator.CreateInstance( typeof(SqlException), BindingFlags.NonPublic | BindingFlags.Instance, - null, - new object?[] { errorMessage, collection, null, Guid.Empty }, + null, + [errorMessage, collection, null, Guid.Empty], null) ?? throw new InvalidOperationException("Failed to create SqlException.")); } @@ -36,7 +36,7 @@ private static SqlErrorCollection GenerateFakeSqlErrorCollection(params SqlError MethodInfo method = type.GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Instance)!; foreach (SqlError error in errors) { - method?.Invoke(collection, new object[] { error }); + method?.Invoke(collection, [error]); } return collection; @@ -47,8 +47,7 @@ public static SqlError GenerateFakeSqlError(int errorCode, string errorMessage = typeof(SqlError), BindingFlags.NonPublic | BindingFlags.Instance, null, - new object?[] - { + [ errorCode, // int infoNumber default(byte), // byte errorState default(byte), // byte errorClass @@ -57,6 +56,6 @@ public static SqlError GenerateFakeSqlError(int errorCode, string errorMessage = string.Empty, // string procedure 0, // int lineNumber null// Exception exception - }, + ], null) ?? throw new InvalidOperationException("Failed to create SqlError")); } \ No newline at end of file diff --git a/Tests/TransientFaultHandling.Tests.Core/StrategyTests.cs b/Tests/TransientFaultHandling.Tests.Core/StrategyTests.cs index d439c89..57f9044 100644 --- a/Tests/TransientFaultHandling.Tests.Core/StrategyTests.cs +++ b/Tests/TransientFaultHandling.Tests.Core/StrategyTests.cs @@ -32,7 +32,7 @@ public void TestTransientErrorIgnoreStrategyWithoutError() [Ignore] // REVIEW public void TestSqlAzureTransientErrorDetectionStrategyWithRetryableError() { - int[] errors = { 40197, 40501, 40540, 10053, 10054, 10060, 40549, 40550, 40551, 40552, 40553, 40613, 40143, 233, 64 }; + int[] errors = [40197, 40501, 40540, 10053, 10054, 10060, 40549, 40550, 40551, 40552, 40553, 40613, 40143, 233, 64]; Type type = typeof(SqlDatabaseTransientErrorDetectionStrategy).GetNestedType("ProcessNetLibErrorCode", BindingFlags.NonPublic)!; errors = errors.AddRange((int[])Enum.GetValues(type)); diff --git a/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestAsyncOperation.cs b/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestAsyncOperation.cs index 4997fb3..685145e 100644 --- a/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestAsyncOperation.cs +++ b/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestAsyncOperation.cs @@ -1,12 +1,10 @@ namespace Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Tests.TestSupport; -public class TestAsyncOperation +public class TestAsyncOperation(Exception exceptionToThrow) { - public TestAsyncOperation(Exception exceptionToThrow) => this.ExceptionToThrow = exceptionToThrow; - public int BeginMethodCount { get; private set; } public int EndMethodCount { get; private set; } - public Exception ExceptionToThrow { get; set; } + public Exception ExceptionToThrow { get; set; } = exceptionToThrow; public IAsyncResult BeginMethod(AsyncCallback callback, object state) { diff --git a/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestRetryStrategy.cs b/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestRetryStrategy.cs index 23184b4..fb75b09 100644 --- a/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestRetryStrategy.cs +++ b/Tests/TransientFaultHandling.Tests.Core/TestSupport/TestRetryStrategy.cs @@ -1,12 +1,8 @@ namespace Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling.Tests.TestSupport; -public class TestRetryStrategy : RetryStrategy +public class TestRetryStrategy() : RetryStrategy(nameof(TestRetryStrategy), true) { - public TestRetryStrategy() - : base(nameof(TestRetryStrategy), true) => - this.CustomProperty = 1; - - public int CustomProperty { get; } + public int CustomProperty { get; } = 1; public int ShouldRetryCount { get; private set; } diff --git a/TransientFaultHandling.Core.sln.DotSettings b/TransientFaultHandling.Core.sln.DotSettings index e8fc57c..237faba 100644 --- a/TransientFaultHandling.Core.sln.DotSettings +++ b/TransientFaultHandling.Core.sln.DotSettings @@ -23,6 +23,7 @@ ERROR ERROR ERROR + ERROR WARNING ERROR ERROR @@ -68,6 +69,7 @@ ERROR ERROR HINT + ERROR ERROR ERROR ERROR