-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathRequestHandlerTypeHelper.cs
More file actions
67 lines (59 loc) · 3.46 KB
/
RequestHandlerTypeHelper.cs
File metadata and controls
67 lines (59 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
namespace softaware.Cqs.DependencyInjection;
internal static class RequestHandlerTypeHelper
{
public static readonly Type GenericRequestHandlerTypeDefinition = typeof(IRequestHandler<,>);
/// <summary>
/// Tries to find the <see cref="IRequestHandler{TRequest, TResult}"/> interfaces with
/// type arguments the provided <paramref name="type"/> implements.
/// The type arguments can either be concrete types, type arguments of the provided
/// <paramref name="type"/>, or a combination - which is currently not supported):
/// <code>
/// class Decorator : IRequestHandler<ICommand, NoResult>
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// class Decorator<TRequest, TResult> : IRequestHandler<TRequest, TResult>
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// class Decorator<TRequest, NoResult> : IRequestHandler<TRequest, NoResult>
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// </code>
/// </summary>
/// <param name="type">The type to search for the <see cref="IRequestHandler{TRequest, TResult}"/> interfaces.</param>
/// <returns>The implemented <see cref="IRequestHandler{TRequest, TResult}"/> interface types
/// with type arguments. Can be empty if none is found.</returns>
public static IEnumerable<Type> GetImplementedRequestHandlerInterfaceTypes(this Type type)
{
var requestHandlerInterfaceTypes = type.GetInterfaces()
.Where(type => type.IsGenericType && type.GetGenericTypeDefinition() == GenericRequestHandlerTypeDefinition);
return requestHandlerInterfaceTypes;
}
/// <summary>
/// Checks if a type is a decorator. For our purpose, we define a decorator as a type implementing <see cref="IRequestHandler{TRequest, TResult}"/>
/// that has a constructor parameter of the same interface type.
/// </summary>
/// <remarks>
/// If the decorator implements multiple <see cref="IRequestHandler{TRequest, TResult}"/> interfaces,
/// it is still a decorator but we don't support this case and treat it as invalid decorator configuration.
/// This distinction is needed so that we don't register this invalid decorator configuration as regular <see cref="IRequestHandler{TRequest, TResult}"/> and therfore avoid registering handlers for the same <see cref="IRequest{TResult}"/> multiple times.
/// </remarks>
/// <param name="type">The type to check.</param>
public static (bool IsDecorator, bool IsValidDecoratorConfiguration) GetDecoratorInfo(this Type type)
{
if (type.IsInterface)
{
return (IsDecorator: false, IsValidDecoratorConfiguration: false);
}
var requestHandlerInterfaceTypes = GetImplementedRequestHandlerInterfaceTypes(type);
if (!requestHandlerInterfaceTypes.Any())
{
return (IsDecorator: false, IsValidDecoratorConfiguration: false);
}
var isDecorator = requestHandlerInterfaceTypes.All(requestHandlerInterfaceType =>
{
var hasConstructorParameterOfSameInterfaceType =
type.GetConstructors()
.SelectMany(c => c.GetParameters())
.Any(p => p.ParameterType == requestHandlerInterfaceType);
return hasConstructorParameterOfSameInterfaceType;
});
return (isDecorator, IsValidDecoratorConfiguration: requestHandlerInterfaceTypes.Count() == 1);
}
}