Skip to content

Commit

Permalink
Merge pull request #518 from rus-art/master
Browse files Browse the repository at this point in the history
Enable Nullable Reference Types
  • Loading branch information
jbogard committed Jun 25, 2020
2 parents 1a38090 + b4e8cf5 commit 2201472
Show file tree
Hide file tree
Showing 17 changed files with 174 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/MediatR/IMediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface IMediator
/// <param name="request">Request object</param>
/// <param name="cancellationToken">Optional cancellation token</param>
/// <returns>A task that represents the send operation. The task result contains the type erased handler response</returns>
Task<object> Send(object request, CancellationToken cancellationToken = default);
Task<object?> Send(object request, CancellationToken cancellationToken = default);

/// <summary>
/// Asynchronously send a notification to multiple handlers
Expand Down
2 changes: 1 addition & 1 deletion src/MediatR/IPipelineBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace MediatR
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public interface IPipelineBehavior<in TRequest, TResponse>
public interface IPipelineBehavior<in TRequest, TResponse> where TRequest : notnull
{
/// <summary>
/// Pipeline handler. Perform any additional behavior and await the <paramref name="next"/> delegate as necessary
Expand Down
1 change: 1 addition & 0 deletions src/MediatR/Internal/HandlersOrderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace MediatR.Internal
internal static class HandlersOrderer
{
public static IList<object> Prioritize<TRequest>(IList<object> handlers, TRequest request)
where TRequest : notnull
{
if (handlers.Count < 2)
{
Expand Down
6 changes: 3 additions & 3 deletions src/MediatR/Internal/RequestHandlerWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace MediatR.Internal

internal abstract class RequestHandlerBase
{
public abstract Task<object> Handle(object request, CancellationToken cancellationToken,
public abstract Task<object?> Handle(object request, CancellationToken cancellationToken,
ServiceFactory serviceFactory);

protected static THandler GetHandler<THandler>(ServiceFactory factory)
Expand Down Expand Up @@ -42,7 +42,7 @@ public abstract Task<TResponse> Handle(IRequest<TResponse> request, Cancellation
internal class RequestHandlerWrapperImpl<TRequest, TResponse> : RequestHandlerWrapper<TResponse>
where TRequest : IRequest<TResponse>
{
public override Task<object> Handle(object request, CancellationToken cancellationToken,
public override Task<object?> Handle(object request, CancellationToken cancellationToken,
ServiceFactory serviceFactory)
{
return Handle((IRequest<TResponse>)request, cancellationToken, serviceFactory)
Expand All @@ -52,7 +52,7 @@ public override Task<object> Handle(object request, CancellationToken cancellati
{
ExceptionDispatchInfo.Capture(t.Exception.InnerException).Throw();
}
return (object)t.Result;
return (object?)t.Result;
}, cancellationToken);
}

Expand Down
4 changes: 3 additions & 1 deletion src/MediatR/MediatR.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
<PropertyGroup>
<Description>Simple, unambitious mediator implementation in .NET</Description>
<Copyright>Copyright Jimmy Bogard</Copyright>
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net461;netstandard2.0;netstandard2.1</TargetFrameworks>
<LangVersion>8</LangVersion>
<Nullable>enable</Nullable>
<AssemblyName>MediatR</AssemblyName>
<PackageId>MediatR</PackageId>
<PackageTags>mediator;request;response;queries;commands;notifications</PackageTags>
Expand Down
4 changes: 2 additions & 2 deletions src/MediatR/Mediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, Cancellation
return handler.Handle(request, cancellationToken, _serviceFactory);
}

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

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

Expand Down
140 changes: 140 additions & 0 deletions src/MediatR/NullableAttributes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#pragma warning disable MA0048 // File name must match type name
#define INTERNAL_NULLABLE_ATTRIBUTES
#if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48

// https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Diagnostics.CodeAnalysis
{
/// <summary>Specifies that null is allowed as an input even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class AllowNullAttribute : Attribute
{ }

/// <summary>Specifies that null is disallowed as an input even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DisallowNullAttribute : Attribute
{ }

/// <summary>Specifies that an output may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MaybeNullAttribute : Attribute
{ }

/// <summary>Specifies that an output will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullAttribute : Attribute
{ }

/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter may be null even if the corresponding type disallows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class MaybeNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter may be null.
/// </param>
public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;

/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}

/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
/// <param name="returnValue">
/// The return value condition. If the method returns this value, the associated parameter will not be null.
/// </param>
public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;

/// <summary>Gets the return value condition.</summary>
public bool ReturnValue { get; }
}

/// <summary>Specifies that the output will be non-null if the named parameter is non-null.</summary>
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class NotNullIfNotNullAttribute : Attribute
{
/// <summary>Initializes the attribute with the associated parameter name.</summary>
/// <param name="parameterName">
/// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
/// </param>
public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;

/// <summary>Gets the associated parameter name.</summary>
public string ParameterName { get; }
}

/// <summary>Applied to a method that will never return under any circumstance.</summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DoesNotReturnAttribute : Attribute
{ }

/// <summary>Specifies that the method will not return if the associated Boolean parameter is passed the specified value.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
#if INTERNAL_NULLABLE_ATTRIBUTES
internal
#else
public
#endif
sealed class DoesNotReturnIfAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified parameter value.</summary>
/// <param name="parameterValue">
/// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
/// the associated parameter matches this value.
/// </param>
public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;

/// <summary>Gets the condition parameter value.</summary>
public bool ParameterValue { get; }
}
}
#endif
4 changes: 4 additions & 0 deletions src/MediatR/Pipeline/IRequestExceptionAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace MediatR.Pipeline
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TException">Exception type</typeparam>
public interface IRequestExceptionAction<in TRequest, in TException>
where TRequest : notnull
where TException : Exception
{
/// <summary>
Expand All @@ -30,6 +31,7 @@ public interface IRequestExceptionAction<in TRequest, in TException>
/// </summary>
/// <typeparam name="TRequest">The type of failed request</typeparam>
public interface IRequestExceptionAction<in TRequest> : IRequestExceptionAction<TRequest, Exception>
where TRequest : notnull
{
}

Expand Down Expand Up @@ -60,6 +62,7 @@ async Task IRequestExceptionAction<TRequest, Exception>.Execute(TRequest request
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TException">Exception type</typeparam>
public abstract class RequestExceptionAction<TRequest, TException> : IRequestExceptionAction<TRequest, TException>
where TRequest : notnull
where TException : Exception
{
Task IRequestExceptionAction<TRequest, TException>.Execute(TRequest request, TException exception, CancellationToken cancellationToken)
Expand All @@ -81,6 +84,7 @@ Task IRequestExceptionAction<TRequest, TException>.Execute(TRequest request, TEx
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
public abstract class RequestExceptionAction<TRequest> : IRequestExceptionAction<TRequest>
where TRequest : notnull
{
Task IRequestExceptionAction<TRequest, Exception>.Execute(TRequest request, Exception exception, CancellationToken cancellationToken)
{
Expand Down
5 changes: 5 additions & 0 deletions src/MediatR/Pipeline/IRequestExceptionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace MediatR.Pipeline
/// <typeparam name="TResponse">Response type</typeparam>
/// <typeparam name="TException">Exception type</typeparam>
public interface IRequestExceptionHandler<in TRequest, TResponse, TException>
where TRequest : notnull
where TException : Exception
{
/// <summary>
Expand All @@ -30,6 +31,7 @@ public interface IRequestExceptionHandler<in TRequest, TResponse, TException>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public interface IRequestExceptionHandler<in TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse, Exception>
where TRequest : notnull
{
}

Expand All @@ -39,6 +41,7 @@ public interface IRequestExceptionHandler<in TRequest, TResponse> : IRequestExce
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public abstract class AsyncRequestExceptionHandler<TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse>
where TRequest : notnull
{
async Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
{
Expand All @@ -62,6 +65,7 @@ async Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequ
/// <typeparam name="TResponse">Response type</typeparam>
/// <typeparam name="TException">Exception type</typeparam>
public abstract class RequestExceptionHandler<TRequest, TResponse, TException> : IRequestExceptionHandler<TRequest, TResponse, TException>
where TRequest : notnull
where TException : Exception
{
Task IRequestExceptionHandler<TRequest, TResponse, TException>.Handle(TRequest request, TException exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
Expand All @@ -85,6 +89,7 @@ Task IRequestExceptionHandler<TRequest, TResponse, TException>.Handle(TRequest r
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public abstract class RequestExceptionHandler<TRequest, TResponse> : IRequestExceptionHandler<TRequest, TResponse>
where TRequest : notnull
{
Task IRequestExceptionHandler<TRequest, TResponse, Exception>.Handle(TRequest request, Exception exception, RequestExceptionHandlerState<TResponse> state, CancellationToken cancellationToken)
{
Expand Down
2 changes: 1 addition & 1 deletion src/MediatR/Pipeline/IRequestPostProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace MediatR.Pipeline
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public interface IRequestPostProcessor<in TRequest, in TResponse>
public interface IRequestPostProcessor<in TRequest, in TResponse> where TRequest : notnull
{
/// <summary>
/// Process method executes after the Handle method on your handler
Expand Down
2 changes: 1 addition & 1 deletion src/MediatR/Pipeline/IRequestPreProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace MediatR.Pipeline
/// Defined a request pre-processor for a handler
/// </summary>
/// <typeparam name="TRequest">Request type</typeparam>
public interface IRequestPreProcessor<in TRequest>
public interface IRequestPreProcessor<in TRequest> where TRequest : notnull
{
/// <summary>
/// Process method executes before calling the Handle method on your handler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace MediatR.Pipeline
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public class RequestExceptionActionProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly ServiceFactory _serviceFactory;

Expand Down
7 changes: 5 additions & 2 deletions src/MediatR/Pipeline/RequestExceptionHandlerState.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Diagnostics.CodeAnalysis;

namespace MediatR.Pipeline
{
/// <summary>
Expand All @@ -14,13 +16,14 @@ public class RequestExceptionHandlerState<TResponse>
/// <summary>
/// The response that is returned if <see cref="Handled"/> is <code>true</code>.
/// </summary>
public TResponse Response { get; private set; }
[MaybeNull]
public TResponse Response { get; private set; } = default!;

/// <summary>
/// Call to indicate whether the current exception should be considered handled and the specified response should be returned.
/// </summary>
/// <param name="response">Set the response that will be returned.</param>
public void SetHandled(TResponse response = default)
public void SetHandled(TResponse response)
{
Handled = true;
Response = response;
Expand Down
5 changes: 3 additions & 2 deletions src/MediatR/Pipeline/RequestExceptionProcessorBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace MediatR.Pipeline
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public class RequestExceptionProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly ServiceFactory _serviceFactory;

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

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

return state.Response;
return state.Response!; //cannot be null if Handled
}
}

Expand Down
1 change: 1 addition & 0 deletions src/MediatR/Pipeline/RequestPostProcessorBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace MediatR.Pipeline
/// <typeparam name="TRequest">Request type</typeparam>
/// <typeparam name="TResponse">Response type</typeparam>
public class RequestPostProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IEnumerable<IRequestPostProcessor<TRequest, TResponse>> _postProcessors;

Expand Down
1 change: 1 addition & 0 deletions src/MediatR/Pipeline/RequestPreProcessorBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace MediatR.Pipeline
/// <typeparam name="TRequest"></typeparam>
/// <typeparam name="TResponse"></typeparam>
public class RequestPreProcessorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IEnumerable<IRequestPreProcessor<TRequest>> _preProcessors;

Expand Down
2 changes: 1 addition & 1 deletion test/MediatR.Tests/MediatR.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net461;netcoreapp2.1</TargetFrameworks>
<TargetFrameworks>net461;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<AssemblyName>MediatR.Tests</AssemblyName>
<PackageId>MediatR.Tests</PackageId>
</PropertyGroup>
Expand Down

0 comments on commit 2201472

Please sign in to comment.