Skip to content

Commit 2201472

Browse files
authored
Merge pull request #518 from rus-art/master
Enable Nullable Reference Types
2 parents 1a38090 + b4e8cf5 commit 2201472

17 files changed

+174
-15
lines changed

src/MediatR/IMediator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public interface IMediator
2424
/// <param name="request">Request object</param>
2525
/// <param name="cancellationToken">Optional cancellation token</param>
2626
/// <returns>A task that represents the send operation. The task result contains the type erased handler response</returns>
27-
Task<object> Send(object request, CancellationToken cancellationToken = default);
27+
Task<object?> Send(object request, CancellationToken cancellationToken = default);
2828

2929
/// <summary>
3030
/// Asynchronously send a notification to multiple handlers

src/MediatR/IPipelineBehavior.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace MediatR
1717
/// </summary>
1818
/// <typeparam name="TRequest">Request type</typeparam>
1919
/// <typeparam name="TResponse">Response type</typeparam>
20-
public interface IPipelineBehavior<in TRequest, TResponse>
20+
public interface IPipelineBehavior<in TRequest, TResponse> where TRequest : notnull
2121
{
2222
/// <summary>
2323
/// Pipeline handler. Perform any additional behavior and await the <paramref name="next"/> delegate as necessary

src/MediatR/Internal/HandlersOrderer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace MediatR.Internal
77
internal static class HandlersOrderer
88
{
99
public static IList<object> Prioritize<TRequest>(IList<object> handlers, TRequest request)
10+
where TRequest : notnull
1011
{
1112
if (handlers.Count < 2)
1213
{

src/MediatR/Internal/RequestHandlerWrapper.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace MediatR.Internal
88

99
internal abstract class RequestHandlerBase
1010
{
11-
public abstract Task<object> Handle(object request, CancellationToken cancellationToken,
11+
public abstract Task<object?> Handle(object request, CancellationToken cancellationToken,
1212
ServiceFactory serviceFactory);
1313

1414
protected static THandler GetHandler<THandler>(ServiceFactory factory)
@@ -42,7 +42,7 @@ public abstract Task<TResponse> Handle(IRequest<TResponse> request, Cancellation
4242
internal class RequestHandlerWrapperImpl<TRequest, TResponse> : RequestHandlerWrapper<TResponse>
4343
where TRequest : IRequest<TResponse>
4444
{
45-
public override Task<object> Handle(object request, CancellationToken cancellationToken,
45+
public override Task<object?> Handle(object request, CancellationToken cancellationToken,
4646
ServiceFactory serviceFactory)
4747
{
4848
return Handle((IRequest<TResponse>)request, cancellationToken, serviceFactory)
@@ -52,7 +52,7 @@ public override Task<object> Handle(object request, CancellationToken cancellati
5252
{
5353
ExceptionDispatchInfo.Capture(t.Exception.InnerException).Throw();
5454
}
55-
return (object)t.Result;
55+
return (object?)t.Result;
5656
}, cancellationToken);
5757
}
5858

src/MediatR/MediatR.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
<PropertyGroup>
44
<Description>Simple, unambitious mediator implementation in .NET</Description>
55
<Copyright>Copyright Jimmy Bogard</Copyright>
6-
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
6+
<TargetFrameworks>net461;netstandard2.0;netstandard2.1</TargetFrameworks>
7+
<LangVersion>8</LangVersion>
8+
<Nullable>enable</Nullable>
79
<AssemblyName>MediatR</AssemblyName>
810
<PackageId>MediatR</PackageId>
911
<PackageTags>mediator;request;response;queries;commands;notifications</PackageTags>

src/MediatR/Mediator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, Cancellation
4141
return handler.Handle(request, cancellationToken, _serviceFactory);
4242
}
4343

44-
public Task<object> Send(object request, CancellationToken cancellationToken = default)
44+
public Task<object?> Send(object request, CancellationToken cancellationToken = default)
4545
{
4646
if (request == null)
4747
{
@@ -58,7 +58,7 @@ public Task<object> Send(object request, CancellationToken cancellationToken = d
5858
throw new ArgumentException($"{nameof(request)} does not implement ${nameof(IRequest)}");
5959
}
6060

61-
var responseType = requestInterfaceType.GetGenericArguments()[0];
61+
var responseType = requestInterfaceType!.GetGenericArguments()[0];
6262
var handler = _requestHandlers.GetOrAdd(requestType,
6363
t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, responseType)));
6464

src/MediatR/NullableAttributes.cs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#pragma warning disable MA0048 // File name must match type name
2+
#define INTERNAL_NULLABLE_ATTRIBUTES
3+
#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48
4+
5+
// https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
6+
7+
// Licensed to the .NET Foundation under one or more agreements.
8+
// The .NET Foundation licenses this file to you under the MIT license.
9+
// See the LICENSE file in the project root for more information.
10+
11+
namespace System.Diagnostics.CodeAnalysis
12+
{
13+
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
14+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
15+
#if INTERNAL_NULLABLE_ATTRIBUTES
16+
internal
17+
#else
18+
public
19+
#endif
20+
sealed class AllowNullAttribute : Attribute
21+
{ }
22+
23+
/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
24+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
25+
#if INTERNAL_NULLABLE_ATTRIBUTES
26+
internal
27+
#else
28+
public
29+
#endif
30+
sealed class DisallowNullAttribute : Attribute
31+
{ }
32+
33+
/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
34+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
35+
#if INTERNAL_NULLABLE_ATTRIBUTES
36+
internal
37+
#else
38+
public
39+
#endif
40+
sealed class MaybeNullAttribute : Attribute
41+
{ }
42+
43+
/// <summary>Specifies that an output will not be null even if the corresponding type allows it.</summary>
44+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
45+
#if INTERNAL_NULLABLE_ATTRIBUTES
46+
internal
47+
#else
48+
public
49+
#endif
50+
sealed class NotNullAttribute : Attribute
51+
{ }
52+
53+
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
54+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
55+
#if INTERNAL_NULLABLE_ATTRIBUTES
56+
internal
57+
#else
58+
public
59+
#endif
60+
sealed class MaybeNullWhenAttribute : Attribute
61+
{
62+
/// <summary>Initializes the attribute with the specified return value condition.</summary>
63+
/// <param name="returnValue">
64+
/// The return value condition. If the method returns this value, the associated parameter may be null.
65+
/// </param>
66+
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
67+
68+
/// <summary>Gets the return value condition.</summary>
69+
public bool ReturnValue { get; }
70+
}
71+
72+
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
73+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
74+
#if INTERNAL_NULLABLE_ATTRIBUTES
75+
internal
76+
#else
77+
public
78+
#endif
79+
sealed class NotNullWhenAttribute : Attribute
80+
{
81+
/// <summary>Initializes the attribute with the specified return value condition.</summary>
82+
/// <param name="returnValue">
83+
/// The return value condition. If the method returns this value, the associated parameter will not be null.
84+
/// </param>
85+
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
86+
87+
/// <summary>Gets the return value condition.</summary>
88+
public bool ReturnValue { get; }
89+
}
90+
91+
/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
92+
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
93+
#if INTERNAL_NULLABLE_ATTRIBUTES
94+
internal
95+
#else
96+
public
97+
#endif
98+
sealed class NotNullIfNotNullAttribute : Attribute
99+
{
100+
/// <summary>Initializes the attribute with the associated parameter name.</summary>
101+
/// <param name="parameterName">
102+
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
103+
/// </param>
104+
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
105+
106+
/// <summary>Gets the associated parameter name.</summary>
107+
public string ParameterName { get; }
108+
}
109+
110+
/// <summary>Applied to a method that will never return under any circumstance.</summary>
111+
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
112+
#if INTERNAL_NULLABLE_ATTRIBUTES
113+
internal
114+
#else
115+
public
116+
#endif
117+
sealed class DoesNotReturnAttribute : Attribute
118+
{ }
119+
120+
/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
121+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
122+
#if INTERNAL_NULLABLE_ATTRIBUTES
123+
internal
124+
#else
125+
public
126+
#endif
127+
sealed class DoesNotReturnIfAttribute : Attribute
128+
{
129+
/// <summary>Initializes the attribute with the specified parameter value.</summary>
130+
/// <param name="parameterValue">
131+
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
132+
/// the associated parameter matches this value.
133+
/// </param>
134+
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
135+
136+
/// <summary>Gets the condition parameter value.</summary>
137+
public bool ParameterValue { get; }
138+
}
139+
}
140+
#endif

src/MediatR/Pipeline/IRequestExceptionAction.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace MediatR.Pipeline
1010
/// <typeparam name="TRequest">Request type</typeparam>
1111
/// <typeparam name="TException">Exception type</typeparam>
1212
public interface IRequestExceptionAction<in TRequest, in TException>
13+
where TRequest : notnull
1314
where TException : Exception
1415
{
1516
/// <summary>
@@ -30,6 +31,7 @@ public interface IRequestExceptionAction<in TRequest, in TException>
3031
/// </summary>
3132
/// <typeparam name="TRequest">The type of failed request</typeparam>
3233
public interface IRequestExceptionAction<in TRequest> : IRequestExceptionAction<TRequest, Exception>
34+
where TRequest : notnull
3335
{
3436
}
3537

@@ -60,6 +62,7 @@ async Task IRequestExceptionAction<TRequest, Exception>.Execute(TRequest request
6062
/// <typeparam name="TRequest">Request type</typeparam>
6163
/// <typeparam name="TException">Exception type</typeparam>
6264
public abstract class RequestExceptionAction<TRequest, TException> : IRequestExceptionAction<TRequest, TException>
65+
where TRequest : notnull
6366
where TException : Exception
6467
{
6568
Task IRequestExceptionAction<TRequest, TException>.Execute(TRequest request, TException exception, CancellationToken cancellationToken)
@@ -81,6 +84,7 @@ Task IRequestExceptionAction<TRequest, TException>.Execute(TRequest request, TEx
8184
/// </summary>
8285
/// <typeparam name="TRequest">Request type</typeparam>
8386
public abstract class RequestExceptionAction<TRequest> : IRequestExceptionAction<TRequest>
87+
where TRequest : notnull
8488
{
8589
Task IRequestExceptionAction<TRequest, Exception>.Execute(TRequest request, Exception exception, CancellationToken cancellationToken)
8690
{

src/MediatR/Pipeline/IRequestExceptionHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace MediatR.Pipeline
1111
/// <typeparam name="TResponse">Response type</typeparam>
1212
/// <typeparam name="TException">Exception type</typeparam>
1313
public interface IRequestExceptionHandler<in TRequest, TResponse, TException>
14+
where TRequest : notnull
1415
where TException : Exception
1516
{
1617
/// <summary>
@@ -30,6 +31,7 @@ public interface IRequestExceptionHandler<in TRequest, TResponse, TException>
3031
/// <typeparam name="TRequest">Request type</typeparam>
3132
/// <typeparam name="TResponse">Response type</typeparam>
3233
public interface IRequestExceptionHandler<in TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse, Exception>
34+
where TRequest : notnull
3335
{
3436
}
3537

@@ -39,6 +41,7 @@ public interface IRequestExceptionHandler<in TRequest, TResponse> : IRequestExce
3941
/// <typeparam name="TRequest">Request type</typeparam>
4042
/// <typeparam name="TResponse">Response type</typeparam>
4143
public abstract class AsyncRequestExceptionHandler<TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse>
44+
where TRequest : notnull
4245
{
4346
async Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
4447
{
@@ -62,6 +65,7 @@ async Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequ
6265
/// <typeparam name="TResponse">Response type</typeparam>
6366
/// <typeparam name="TException">Exception type</typeparam>
6467
public abstract class RequestExceptionHandler<TRequest, TResponse, TException> : IRequestExceptionHandler<TRequest, TResponse, TException>
68+
where TRequest : notnull
6569
where TException : Exception
6670
{
6771
Task IRequestExceptionHandler<TRequest, TResponse, TException>.Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
@@ -85,6 +89,7 @@ Task IRequestExceptionHandler<TRequest, TResponse, TException>.Handle(TRequest r
8589
/// <typeparam name="TRequest">Request type</typeparam>
8690
/// <typeparam name="TResponse">Response type</typeparam>
8791
public abstract class RequestExceptionHandler<TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse>
92+
where TRequest : notnull
8893
{
8994
Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
9095
{

src/MediatR/Pipeline/IRequestPostProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace MediatR.Pipeline
88
/// </summary>
99
/// <typeparam name="TRequest">Request type</typeparam>
1010
/// <typeparam name="TResponse">Response type</typeparam>
11-
public interface IRequestPostProcessor<in TRequest, in TResponse>
11+
public interface IRequestPostProcessor<in TRequest, in TResponse> where TRequest : notnull
1212
{
1313
/// <summary>
1414
/// Process method executes after the Handle method on your handler

src/MediatR/Pipeline/IRequestPreProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace MediatR.Pipeline
77
/// Defined a request pre-processor for a handler
88
/// </summary>
99
/// <typeparam name="TRequest">Request type</typeparam>
10-
public interface IRequestPreProcessor<in TRequest>
10+
public interface IRequestPreProcessor<in TRequest> where TRequest : notnull
1111
{
1212
/// <summary>
1313
/// Process method executes before calling the Handle method on your handler

src/MediatR/Pipeline/RequestExceptionActionProcessorBehavior.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace MediatR.Pipeline
1616
/// <typeparam name="TRequest">Request type</typeparam>
1717
/// <typeparam name="TResponse">Response type</typeparam>
1818
public class RequestExceptionActionProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
19+
where TRequest : notnull
1920
{
2021
private readonly ServiceFactory _serviceFactory;
2122

src/MediatR/Pipeline/RequestExceptionHandlerState.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
13
namespace MediatR.Pipeline
24
{
35
/// <summary>
@@ -14,13 +16,14 @@ public class RequestExceptionHandlerState<TResponse>
1416
/// <summary>
1517
/// The response that is returned if <see cref="Handled"/> is <code>true</code>.
1618
/// </summary>
17-
public TResponse Response { get; private set; }
19+
[MaybeNull]
20+
public TResponse Response { get; private set; } = default!;
1821

1922
/// <summary>
2023
/// Call to indicate whether the current exception should be considered handled and the specified response should be returned.
2124
/// </summary>
2225
/// <param name="response">Set the response that will be returned.</param>
23-
public void SetHandled(TResponse response = default)
26+
public void SetHandled(TResponse response)
2427
{
2528
Handled = true;
2629
Response = response;

src/MediatR/Pipeline/RequestExceptionProcessorBehavior.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace MediatR.Pipeline
1616
/// <typeparam name="TRequest">Request type</typeparam>
1717
/// <typeparam name="TResponse">Response type</typeparam>
1818
public class RequestExceptionProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
19+
where TRequest : notnull
1920
{
2021
private readonly ServiceFactory _serviceFactory;
2122

@@ -30,7 +31,7 @@ public async Task<TResponse> Handle(TRequest request, CancellationToken cancella
3031
catch (Exception exception)
3132
{
3233
var state = new RequestExceptionHandlerState<TResponse>();
33-
Type exceptionType = null;
34+
Type? exceptionType = null;
3435

3536
while (!state.Handled && exceptionType != typeof(Exception))
3637
{
@@ -53,7 +54,7 @@ public async Task<TResponse> Handle(TRequest request, CancellationToken cancella
5354
throw;
5455
}
5556

56-
return state.Response;
57+
return state.Response!; //cannot be null if Handled
5758
}
5859
}
5960

src/MediatR/Pipeline/RequestPostProcessorBehavior.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace MediatR.Pipeline
1010
/// <typeparam name="TRequest">Request type</typeparam>
1111
/// <typeparam name="TResponse">Response type</typeparam>
1212
public class RequestPostProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
13+
where TRequest : notnull
1314
{
1415
private readonly IEnumerable<IRequestPostProcessor<TRequest, TResponse>> _postProcessors;
1516

src/MediatR/Pipeline/RequestPreProcessorBehavior.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ namespace MediatR.Pipeline
1010
/// <typeparam name="TRequest"></typeparam>
1111
/// <typeparam name="TResponse"></typeparam>
1212
public class RequestPreProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
13+
where TRequest : notnull
1314
{
1415
private readonly IEnumerable<IRequestPreProcessor<TRequest>> _preProcessors;
1516

test/MediatR.Tests/MediatR.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
4+
<TargetFrameworks>net461;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
55
<AssemblyName>MediatR.Tests</AssemblyName>
66
<PackageId>MediatR.Tests</PackageId>
77
</PropertyGroup>

0 commit comments

Comments
 (0)