@@ -8,15 +8,23 @@ namespace JsonApiDotNetCore.Configuration;
88/// </summary>
99internal sealed class TypeLocator
1010{
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+
1119 /// <summary>
1220 /// Attempts to lookup the ID type of the specified resource type. Returns <c>null</c> if it does not implement <see cref="IIdentifiable{TId}" />.
1321 /// </summary>
1422 public Type ? LookupIdType ( Type ? resourceClrType )
1523 {
16- Type ? identifiableInterface = resourceClrType ? . GetInterfaces ( ) . FirstOrDefault ( @interface =>
24+ Type ? identifiableClosedInterface = resourceClrType ? . GetInterfaces ( ) . FirstOrDefault ( @interface =>
1725 @interface . IsGenericType && @interface . GetGenericTypeDefinition ( ) == typeof ( IIdentifiable < > ) ) ;
1826
19- return identifiableInterface ? . GetGenericArguments ( ) [ 0 ] ;
27+ return identifiableClosedInterface ? . GetGenericArguments ( ) [ 0 ] ;
2028 }
2129
2230 /// <summary>
@@ -38,62 +46,62 @@ internal sealed class TypeLocator
3846 }
3947
4048 /// <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.
4251 /// </summary>
4352 /// <param name="assembly">
44- /// The assembly to search in .
53+ /// The assembly to search for matching types .
4554 /// </param>
46- /// <param name="openGenericInterface ">
47- /// The open generic interface.
55+ /// <param name="openInterface ">
56+ /// The open generic interface to match against .
4857 /// </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" /> .
5160 /// </param>
5261 /// <example>
5362 /// <code><![CDATA[
54- /// GetGenericInterfaceImplementation (assembly, typeof(IResourceService<,>), typeof(Article), typeof(Guid));
63+ /// GetContainerRegistrationFromAssembly (assembly, typeof(IResourceService<,>), typeof(Article), typeof(Guid));
5564 /// ]]></code>
5665 /// </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 )
5968 {
6069 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 ) ) ;
6372
64- if ( ! openGenericInterface . IsInterface || ! openGenericInterface . IsGenericType || openGenericInterface != openGenericInterface . GetGenericTypeDefinition ( ) )
73+ if ( ! openInterface . IsInterface || ! openInterface . IsGenericType || openInterface != openInterface . GetGenericTypeDefinition ( ) )
6574 {
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 ) ) ;
6776 }
6877
69- if ( interfaceGenericTypeArguments . Length != openGenericInterface . GetGenericArguments ( ) . Length )
78+ if ( interfaceTypeArguments . Length != openInterface . GetGenericArguments ( ) . Length )
7079 {
7180 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 ) ) ;
7483 }
7584
76- return assembly . GetTypes ( ) . Select ( type => FindGenericInterfaceImplementationForType ( type , openGenericInterface , interfaceGenericTypeArguments ) )
85+ return assembly . GetTypes ( ) . Select ( type => GetContainerRegistrationFromType ( type , openInterface , interfaceTypeArguments ) )
7786 . FirstOrDefault ( result => result != null ) ;
7887 }
7988
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 )
8291 {
8392 if ( ! nextType . IsNested )
8493 {
85- foreach ( Type nextGenericInterface in nextType . GetInterfaces ( ) . Where ( type => type . IsGenericType ) )
94+ foreach ( Type nextConstructedInterface in nextType . GetInterfaces ( ) . Where ( type => type . IsGenericType ) )
8695 {
87- Type nextOpenGenericInterface = nextGenericInterface . GetGenericTypeDefinition ( ) ;
96+ Type nextOpenInterface = nextConstructedInterface . GetGenericTypeDefinition ( ) ;
8897
89- if ( nextOpenGenericInterface == openGenericInterface )
98+ if ( nextOpenInterface == openInterface )
9099 {
91- Type [ ] nextGenericArguments = nextGenericInterface . GetGenericArguments ( ) ;
100+ Type [ ] nextTypeArguments = nextConstructedInterface . GetGenericArguments ( ) ;
92101
93- if ( nextGenericArguments . Length == interfaceGenericTypeArguments . Length &&
94- nextGenericArguments . SequenceEqual ( interfaceGenericTypeArguments ) )
102+ if ( nextTypeArguments . Length == interfaceTypeArguments . Length && nextTypeArguments . SequenceEqual ( interfaceTypeArguments ) )
95103 {
96- return ( nextType , nextOpenGenericInterface . MakeGenericType ( interfaceGenericTypeArguments ) ) ;
104+ return ( nextType , nextOpenInterface . MakeGenericType ( interfaceTypeArguments ) ) ;
97105 }
98106 }
99107 }
@@ -103,30 +111,30 @@ private static (Type implementation, Type registrationInterface)? FindGenericInt
103111 }
104112
105113 /// <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.
107115 /// </summary>
108116 /// <param name="assembly">
109- /// The assembly to search.
117+ /// The assembly to search for derived types .
110118 /// </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 .
113121 /// </param>
114- /// <param name="genericArguments ">
115- /// Parameters to the generic type .
122+ /// <param name="typeArguments ">
123+ /// Generic type arguments to construct <paramref name="openType" /> .
116124 /// </param>
117125 /// <example>
118126 /// <code><![CDATA[
119- /// GetDerivedGenericTypes (assembly, typeof(ResourceDefinition<>), typeof(Article))
127+ /// GetDerivedTypesForOpenType (assembly, typeof(ResourceDefinition<, >), typeof(Article), typeof(int ))
120128 /// ]]></code>
121129 /// </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 )
123131 {
124132 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 ) ) ;
127135
128- Type genericType = openGenericType . MakeGenericType ( genericArguments ) ;
129- return GetDerivedTypes ( assembly , genericType ) . ToArray ( ) ;
136+ Type closedType = openType . MakeGenericType ( typeArguments ) ;
137+ return GetDerivedTypes ( assembly , closedType ) . ToArray ( ) ;
130138 }
131139
132140 /// <summary>
@@ -135,22 +143,22 @@ public IReadOnlyCollection<Type> GetDerivedGenericTypes(Assembly assembly, Type
135143 /// <param name="assembly">
136144 /// The assembly to search.
137145 /// </param>
138- /// <param name="inheritedType ">
146+ /// <param name="baseType ">
139147 /// The inherited type.
140148 /// </param>
141149 /// <example>
142150 /// <code>
143- /// GetDerivedGenericTypes (assembly, typeof(DbContext))
151+ /// GetDerivedTypes (assembly, typeof(DbContext))
144152 /// </code>
145153 /// </example>
146- public IEnumerable < Type > GetDerivedTypes ( Assembly assembly , Type inheritedType )
154+ public IEnumerable < Type > GetDerivedTypes ( Assembly assembly , Type baseType )
147155 {
148156 ArgumentGuard . NotNull ( assembly , nameof ( assembly ) ) ;
149- ArgumentGuard . NotNull ( inheritedType , nameof ( inheritedType ) ) ;
157+ ArgumentGuard . NotNull ( baseType , nameof ( baseType ) ) ;
150158
151159 foreach ( Type type in assembly . GetTypes ( ) )
152160 {
153- if ( inheritedType . IsAssignableFrom ( type ) )
161+ if ( baseType . IsAssignableFrom ( type ) )
154162 {
155163 yield return type ;
156164 }
0 commit comments