@@ -8,15 +8,23 @@ namespace JsonApiDotNetCore.Configuration;
8
8
/// </summary>
9
9
internal sealed class TypeLocator
10
10
{
11
+ // As a reminder, the following terminology is used for generic types:
12
+ // non-generic string
13
+ // generic
14
+ // unbound Dictionary<,>
15
+ // constructed
16
+ // open Dictionary<TKey,TValue>
17
+ // closed Dictionary<string,int>
18
+
11
19
/// <summary>
12
20
/// Attempts to lookup the ID type of the specified resource type. Returns <c>null</c> if it does not implement <see cref="IIdentifiable{TId}" />.
13
21
/// </summary>
14
22
public Type ? LookupIdType ( Type ? resourceClrType )
15
23
{
16
- Type ? identifiableInterface = resourceClrType ? . GetInterfaces ( ) . FirstOrDefault ( @interface =>
24
+ Type ? identifiableClosedInterface = resourceClrType ? . GetInterfaces ( ) . FirstOrDefault ( @interface =>
17
25
@interface . IsGenericType && @interface . GetGenericTypeDefinition ( ) == typeof ( IIdentifiable < > ) ) ;
18
26
19
- return identifiableInterface ? . GetGenericArguments ( ) [ 0 ] ;
27
+ return identifiableClosedInterface ? . GetGenericArguments ( ) [ 0 ] ;
20
28
}
21
29
22
30
/// <summary>
@@ -38,62 +46,62 @@ internal sealed class TypeLocator
38
46
}
39
47
40
48
/// <summary>
41
- /// Gets all implementations of a generic interface.
49
+ /// Gets the implementation type with service interface (to be registered in the IoC container) for the specified open interface and its type arguments,
50
+ /// by scanning for types in the specified assembly that match the signature.
42
51
/// </summary>
43
52
/// <param name="assembly">
44
- /// The assembly to search in .
53
+ /// The assembly to search for matching types .
45
54
/// </param>
46
- /// <param name="openGenericInterface ">
47
- /// The open generic interface.
55
+ /// <param name="openInterface ">
56
+ /// The open generic interface to match against .
48
57
/// </param>
49
- /// <param name="interfaceGenericTypeArguments ">
50
- /// Generic type parameters to construct the generic interface .
58
+ /// <param name="interfaceTypeArguments ">
59
+ /// Generic type arguments to construct <paramref name="openInterface" /> .
51
60
/// </param>
52
61
/// <example>
53
62
/// <code><![CDATA[
54
- /// GetGenericInterfaceImplementation (assembly, typeof(IResourceService<,>), typeof(Article), typeof(Guid));
63
+ /// GetContainerRegistrationFromAssembly (assembly, typeof(IResourceService<,>), typeof(Article), typeof(Guid));
55
64
/// ]]></code>
56
65
/// </example>
57
- public ( Type implementation , Type registrationInterface ) ? GetGenericInterfaceImplementation ( Assembly assembly , Type openGenericInterface ,
58
- params Type [ ] interfaceGenericTypeArguments )
66
+ public ( Type implementationType , Type serviceInterface ) ? GetContainerRegistrationFromAssembly ( Assembly assembly , Type openInterface ,
67
+ params Type [ ] interfaceTypeArguments )
59
68
{
60
69
ArgumentGuard . NotNull ( assembly , nameof ( assembly ) ) ;
61
- ArgumentGuard . NotNull ( openGenericInterface , nameof ( openGenericInterface ) ) ;
62
- ArgumentGuard . NotNull ( interfaceGenericTypeArguments , nameof ( interfaceGenericTypeArguments ) ) ;
70
+ ArgumentGuard . NotNull ( openInterface , nameof ( openInterface ) ) ;
71
+ ArgumentGuard . NotNull ( interfaceTypeArguments , nameof ( interfaceTypeArguments ) ) ;
63
72
64
- if ( ! openGenericInterface . IsInterface || ! openGenericInterface . IsGenericType || openGenericInterface != openGenericInterface . GetGenericTypeDefinition ( ) )
73
+ if ( ! openInterface . IsInterface || ! openInterface . IsGenericType || openInterface != openInterface . GetGenericTypeDefinition ( ) )
65
74
{
66
- throw new ArgumentException ( $ "Specified type '{ openGenericInterface . FullName } ' is not an open generic interface.", nameof ( openGenericInterface ) ) ;
75
+ throw new ArgumentException ( $ "Specified type '{ openInterface . FullName } ' is not an open generic interface.", nameof ( openInterface ) ) ;
67
76
}
68
77
69
- if ( interfaceGenericTypeArguments . Length != openGenericInterface . GetGenericArguments ( ) . Length )
78
+ if ( interfaceTypeArguments . Length != openInterface . GetGenericArguments ( ) . Length )
70
79
{
71
80
throw new ArgumentException (
72
- $ "Interface '{ openGenericInterface . FullName } ' requires { openGenericInterface . GetGenericArguments ( ) . Length } type parameters " +
73
- $ "instead of { interfaceGenericTypeArguments . Length } .", nameof ( interfaceGenericTypeArguments ) ) ;
81
+ $ "Interface '{ openInterface . FullName } ' requires { openInterface . GetGenericArguments ( ) . Length } type arguments " +
82
+ $ "instead of { interfaceTypeArguments . Length } .", nameof ( interfaceTypeArguments ) ) ;
74
83
}
75
84
76
- return assembly . GetTypes ( ) . Select ( type => FindGenericInterfaceImplementationForType ( type , openGenericInterface , interfaceGenericTypeArguments ) )
85
+ return assembly . GetTypes ( ) . Select ( type => GetContainerRegistrationFromType ( type , openInterface , interfaceTypeArguments ) )
77
86
. FirstOrDefault ( result => result != null ) ;
78
87
}
79
88
80
- private static ( Type implementation , Type registrationInterface ) ? FindGenericInterfaceImplementationForType ( Type nextType , Type openGenericInterface ,
81
- Type [ ] interfaceGenericTypeArguments )
89
+ private static ( Type implementationType , Type serviceInterface ) ? GetContainerRegistrationFromType ( Type nextType , Type openInterface ,
90
+ Type [ ] interfaceTypeArguments )
82
91
{
83
92
if ( ! nextType . IsNested )
84
93
{
85
- foreach ( Type nextGenericInterface in nextType . GetInterfaces ( ) . Where ( type => type . IsGenericType ) )
94
+ foreach ( Type nextConstructedInterface in nextType . GetInterfaces ( ) . Where ( type => type . IsGenericType ) )
86
95
{
87
- Type nextOpenGenericInterface = nextGenericInterface . GetGenericTypeDefinition ( ) ;
96
+ Type nextOpenInterface = nextConstructedInterface . GetGenericTypeDefinition ( ) ;
88
97
89
- if ( nextOpenGenericInterface == openGenericInterface )
98
+ if ( nextOpenInterface == openInterface )
90
99
{
91
- Type [ ] nextGenericArguments = nextGenericInterface . GetGenericArguments ( ) ;
100
+ Type [ ] nextTypeArguments = nextConstructedInterface . GetGenericArguments ( ) ;
92
101
93
- if ( nextGenericArguments . Length == interfaceGenericTypeArguments . Length &&
94
- nextGenericArguments . SequenceEqual ( interfaceGenericTypeArguments ) )
102
+ if ( nextTypeArguments . Length == interfaceTypeArguments . Length && nextTypeArguments . SequenceEqual ( interfaceTypeArguments ) )
95
103
{
96
- return ( nextType , nextOpenGenericInterface . MakeGenericType ( interfaceGenericTypeArguments ) ) ;
104
+ return ( nextType , nextOpenInterface . MakeGenericType ( interfaceTypeArguments ) ) ;
97
105
}
98
106
}
99
107
}
@@ -103,30 +111,30 @@ private static (Type implementation, Type registrationInterface)? FindGenericInt
103
111
}
104
112
105
113
/// <summary>
106
- /// Gets all derivatives of the concrete, generic type.
114
+ /// Scans for types in the specified assembly that derive from the specified open type.
107
115
/// </summary>
108
116
/// <param name="assembly">
109
- /// The assembly to search.
117
+ /// The assembly to search for derived types .
110
118
/// </param>
111
- /// <param name="openGenericType ">
112
- /// The open generic type, e.g. `typeof(ResourceDefinition<>)` .
119
+ /// <param name="openType ">
120
+ /// The open generic interface to match against .
113
121
/// </param>
114
- /// <param name="genericArguments ">
115
- /// Parameters to the generic type .
122
+ /// <param name="typeArguments ">
123
+ /// Generic type arguments to construct <paramref name="openType" /> .
116
124
/// </param>
117
125
/// <example>
118
126
/// <code><![CDATA[
119
- /// GetDerivedGenericTypes (assembly, typeof(ResourceDefinition<>), typeof(Article))
127
+ /// GetDerivedTypesForOpenType (assembly, typeof(ResourceDefinition<, >), typeof(Article), typeof(int ))
120
128
/// ]]></code>
121
129
/// </example>
122
- public IReadOnlyCollection < Type > GetDerivedGenericTypes ( Assembly assembly , Type openGenericType , params Type [ ] genericArguments )
130
+ public IReadOnlyCollection < Type > GetDerivedTypesForOpenType ( Assembly assembly , Type openType , params Type [ ] typeArguments )
123
131
{
124
132
ArgumentGuard . NotNull ( assembly , nameof ( assembly ) ) ;
125
- ArgumentGuard . NotNull ( openGenericType , nameof ( openGenericType ) ) ;
126
- ArgumentGuard . NotNull ( genericArguments , nameof ( genericArguments ) ) ;
133
+ ArgumentGuard . NotNull ( openType , nameof ( openType ) ) ;
134
+ ArgumentGuard . NotNull ( typeArguments , nameof ( typeArguments ) ) ;
127
135
128
- Type genericType = openGenericType . MakeGenericType ( genericArguments ) ;
129
- return GetDerivedTypes ( assembly , genericType ) . ToArray ( ) ;
136
+ Type closedType = openType . MakeGenericType ( typeArguments ) ;
137
+ return GetDerivedTypes ( assembly , closedType ) . ToArray ( ) ;
130
138
}
131
139
132
140
/// <summary>
@@ -135,22 +143,22 @@ public IReadOnlyCollection<Type> GetDerivedGenericTypes(Assembly assembly, Type
135
143
/// <param name="assembly">
136
144
/// The assembly to search.
137
145
/// </param>
138
- /// <param name="inheritedType ">
146
+ /// <param name="baseType ">
139
147
/// The inherited type.
140
148
/// </param>
141
149
/// <example>
142
150
/// <code>
143
- /// GetDerivedGenericTypes (assembly, typeof(DbContext))
151
+ /// GetDerivedTypes (assembly, typeof(DbContext))
144
152
/// </code>
145
153
/// </example>
146
- public IEnumerable < Type > GetDerivedTypes ( Assembly assembly , Type inheritedType )
154
+ public IEnumerable < Type > GetDerivedTypes ( Assembly assembly , Type baseType )
147
155
{
148
156
ArgumentGuard . NotNull ( assembly , nameof ( assembly ) ) ;
149
- ArgumentGuard . NotNull ( inheritedType , nameof ( inheritedType ) ) ;
157
+ ArgumentGuard . NotNull ( baseType , nameof ( baseType ) ) ;
150
158
151
159
foreach ( Type type in assembly . GetTypes ( ) )
152
160
{
153
- if ( inheritedType . IsAssignableFrom ( type ) )
161
+ if ( baseType . IsAssignableFrom ( type ) )
154
162
{
155
163
yield return type ;
156
164
}
0 commit comments