diff --git a/src/Polly/Timeout/TimeoutPolicy.cs b/src/Polly/Timeout/TimeoutPolicy.cs
index 1f638ccceae..2e05f6a144e 100644
--- a/src/Polly/Timeout/TimeoutPolicy.cs
+++ b/src/Polly/Timeout/TimeoutPolicy.cs
@@ -3,7 +3,6 @@
///
/// A timeout policy which can be applied to delegates.
///
-#pragma warning disable CA1062 // Validate arguments of public methods
public class TimeoutPolicy : Policy, ITimeoutPolicy
{
private readonly TimeoutStrategy _timeoutStrategy;
@@ -22,14 +21,21 @@ internal TimeoutPolicy(
///
[DebuggerStepThrough]
- protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) =>
- TimeoutEngine.Implementation(
+ protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken)
+ {
+ if (action is null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+
+ return TimeoutEngine.Implementation(
action,
context,
_timeoutProvider,
_timeoutStrategy,
_onTimeout,
cancellationToken);
+ }
}
///
@@ -53,12 +59,19 @@ internal TimeoutPolicy(
}
///
- protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken) =>
- TimeoutEngine.Implementation(
+ protected override TResult Implementation(Func action, Context context, CancellationToken cancellationToken)
+ {
+ if (action is null)
+ {
+ throw new ArgumentNullException(nameof(action));
+ }
+
+ return TimeoutEngine.Implementation(
action,
context,
_timeoutProvider,
_timeoutStrategy,
_onTimeout,
cancellationToken);
+ }
}
diff --git a/test/Polly.Specs/Timeout/TimeoutSpecs.cs b/test/Polly.Specs/Timeout/TimeoutSpecs.cs
index d7e1ea34481..76e1cdf5d55 100644
--- a/test/Polly.Specs/Timeout/TimeoutSpecs.cs
+++ b/test/Polly.Specs/Timeout/TimeoutSpecs.cs
@@ -5,6 +5,34 @@ public class TimeoutSpecs : TimeoutSpecsBase
{
#region Configuration
+ [Fact]
+ public void Should_throw_when_action_is_null()
+ {
+ var flags = BindingFlags.NonPublic | BindingFlags.Instance;
+ Func action = null!;
+ Func timeoutProvider = (_) => TimeSpan.Zero;
+ TimeoutStrategy timeoutStrategy = TimeoutStrategy.Optimistic;
+ Action onTimeout = (_, _, _, _) => { };
+
+ var instance = Activator.CreateInstance(
+ typeof(TimeoutPolicy),
+ flags,
+ null,
+ [timeoutProvider, timeoutStrategy, onTimeout],
+ null)!;
+ var instanceType = instance.GetType();
+ var methods = instanceType.GetMethods(flags);
+ var methodInfo = methods.First(method => method is { Name: "Implementation", ReturnType.Name: "TResult" });
+ var generic = methodInfo.MakeGenericMethod(typeof(EmptyStruct));
+
+ var func = () => generic.Invoke(instance, [action, new Context(), CancellationToken.None]);
+
+ var exceptionAssertions = func.Should().Throw();
+ exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation.");
+ exceptionAssertions.And.InnerException.Should().BeOfType()
+ .Which.ParamName.Should().Be("action");
+ }
+
[Fact]
public void Should_throw_when_timeout_is_zero_by_timespan()
{
diff --git a/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs b/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs
index 202ed090380..18330810f67 100644
--- a/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs
+++ b/test/Polly.Specs/Timeout/TimeoutTResultSpecs.cs
@@ -5,6 +5,33 @@ public class TimeoutTResultSpecs : TimeoutSpecsBase
{
#region Configuration
+ [Fact]
+ public void Should_throw_when_action_is_null()
+ {
+ var flags = BindingFlags.NonPublic | BindingFlags.Instance;
+ Func action = null!;
+ Func timeoutProvider = (_) => TimeSpan.Zero;
+ TimeoutStrategy timeoutStrategy = TimeoutStrategy.Optimistic;
+ Action onTimeout = (_, _, _, _) => { };
+
+ var instance = Activator.CreateInstance(
+ typeof(TimeoutPolicy),
+ flags,
+ null,
+ [timeoutProvider, timeoutStrategy, onTimeout],
+ null)!;
+ var instanceType = instance.GetType();
+ var methods = instanceType.GetMethods(flags);
+ var methodInfo = methods.First(method => method is { Name: "Implementation", ReturnType.Name: "EmptyStruct" });
+
+ var func = () => methodInfo.Invoke(instance, [action, new Context(), CancellationToken.None]);
+
+ var exceptionAssertions = func.Should().Throw();
+ exceptionAssertions.And.Message.Should().Be("Exception has been thrown by the target of an invocation.");
+ exceptionAssertions.And.InnerException.Should().BeOfType()
+ .Which.ParamName.Should().Be("action");
+ }
+
[Fact]
public void Should_throw_when_timeout_is_zero_by_timespan()
{