@@ -143,6 +143,7 @@ public static bool IsSyntaxTarget(SyntaxNode syntaxNode, CancellationToken token
143
143
// Create the model fully describing the current service registration
144
144
serviceInfo . Add ( new RegisteredServiceInfo (
145
145
RegistrationKind : registrationKind ,
146
+ ImplementationTypeName : implementationType . Name ,
146
147
ImplementationFullyQualifiedTypeName : implementationTypeName ,
147
148
ServiceFullyQualifiedTypeNames : serviceTypeNames ,
148
149
RequiredServiceFullyQualifiedTypeNames : constructorArgumentTypes ) ) ;
@@ -166,8 +167,11 @@ public static bool IsSyntaxTarget(SyntaxNode syntaxNode, CancellationToken token
166
167
/// <returns>A <see cref="CompilationUnitSyntax"/> instance with the gathered info.</returns>
167
168
public static CompilationUnitSyntax GetSyntax ( ServiceCollectionInfo info )
168
169
{
170
+ using ImmutableArrayBuilder < LocalFunctionStatementSyntax > localFunctions = ImmutableArrayBuilder < LocalFunctionStatementSyntax > . Rent ( ) ;
169
171
using ImmutableArrayBuilder < StatementSyntax > registrationStatements = ImmutableArrayBuilder < StatementSyntax > . Rent ( ) ;
170
172
173
+ int index = - 1 ;
174
+
171
175
foreach ( RegisteredServiceInfo serviceInfo in info . Services )
172
176
{
173
177
// The first service type always acts as "main" registration, and should always be present
@@ -176,6 +180,9 @@ public static CompilationUnitSyntax GetSyntax(ServiceCollectionInfo info)
176
180
continue ;
177
181
}
178
182
183
+ // Increment the index we use to disambiguate the generated local function names (starting from 0)
184
+ index ++ ;
185
+
179
186
using ImmutableArrayBuilder < ArgumentSyntax > constructorArguments = ImmutableArrayBuilder < ArgumentSyntax > . Rent ( ) ;
180
187
181
188
// Prepare the dependent services for the implementation type
@@ -199,54 +206,55 @@ public static CompilationUnitSyntax GetSyntax(ServiceCollectionInfo info)
199
206
// Prepare the method name, either AddSingleton or AddTransient
200
207
string registrationMethod = $ "Add{ serviceInfo . RegistrationKind } ";
201
208
202
- // Special case when the service is a singleton and no dependent services are present, just use eager instantiation instead:
209
+ // Prepare the name of the factory local function
210
+ string factoryMethod = $ "Get{ serviceInfo . ImplementationTypeName } _{ index } ";
211
+
212
+ // Prepare the local function for the registration (to improve lambda caching):
203
213
//
204
- // global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton(<PARAMETER_NAME>, typeof(<ROOT_SERVICE_TYPE>), new <IMPLEMENTATION_TYPE>());
205
- if ( serviceInfo . RegistrationKind == ServiceRegistrationKind . Singleton && constructorArguments . Count == 0 )
206
- {
207
- registrationStatements . Add (
208
- ExpressionStatement (
209
- InvocationExpression (
210
- MemberAccessExpression (
211
- SyntaxKind . SimpleMemberAccessExpression ,
212
- IdentifierName ( "global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions" ) ,
213
- IdentifierName ( "AddSingleton" ) ) )
214
- . AddArgumentListArguments (
215
- Argument ( IdentifierName ( info . Method . ServiceCollectionParameterName ) ) ,
216
- Argument ( TypeOfExpression ( IdentifierName ( rootServiceTypeName ) ) ) ,
217
- Argument (
218
- ObjectCreationExpression ( IdentifierName ( serviceInfo . ImplementationFullyQualifiedTypeName ) )
219
- . WithArgumentList ( ArgumentList ( ) ) ) ) ) ) ;
220
- }
221
- else
222
- {
223
- // Register the main implementation type when at least a dependent service is needed:
224
- //
225
- // global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.<REGISTRATION_METHOD>(<PARAMETER_NAME>, typeof(<ROOT_SERVICE_TYPE>), static services => new <IMPLEMENTATION_TYPE>(<CONSTRUCTOR_ARGUMENTS>));
226
- registrationStatements . Add (
227
- ExpressionStatement (
228
- InvocationExpression (
229
- MemberAccessExpression (
230
- SyntaxKind . SimpleMemberAccessExpression ,
231
- IdentifierName ( "global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions" ) ,
232
- IdentifierName ( registrationMethod ) ) )
233
- . AddArgumentListArguments (
234
- Argument ( IdentifierName ( info . Method . ServiceCollectionParameterName ) ) ,
235
- Argument ( TypeOfExpression ( IdentifierName ( rootServiceTypeName ) ) ) ,
236
- Argument (
237
- SimpleLambdaExpression ( Parameter ( Identifier ( "services" ) ) )
238
- . AddModifiers ( Token ( SyntaxKind . StaticKeyword ) )
239
- . WithExpressionBody (
240
- ObjectCreationExpression ( IdentifierName ( serviceInfo . ImplementationFullyQualifiedTypeName ) )
241
- . AddArgumentListArguments ( constructorArguments . ToArray ( ) ) ) ) ) ) ) ;
242
- }
214
+ // static object <FACTORY_METHOD>(global::System.IServiceProvider services)
215
+ // {
216
+ // return new <IMPLEMENTATION_TYPE>(<CONSTRUCTOR_ARGUMENTS>);
217
+ // }
218
+ localFunctions . Add (
219
+ LocalFunctionStatement (
220
+ PredefinedType ( Token ( SyntaxKind . ObjectKeyword ) ) ,
221
+ Identifier ( factoryMethod ) )
222
+ . AddModifiers ( Token ( SyntaxKind . StaticKeyword ) )
223
+ . AddParameterListParameters (
224
+ Parameter ( Identifier ( "services" ) )
225
+ . WithType ( IdentifierName ( "global::System.IServiceProvider" ) ) )
226
+ . AddBodyStatements (
227
+ ReturnStatement (
228
+ ObjectCreationExpression ( IdentifierName ( serviceInfo . ImplementationFullyQualifiedTypeName ) )
229
+ . AddArgumentListArguments ( constructorArguments . ToArray ( ) ) ) ) ) ;
230
+
231
+ // Register the main implementation type:
232
+ //
233
+ // global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.<REGISTRATION_METHOD>(<PARAMETER_NAME>, typeof(<ROOT_SERVICE_TYPE>), new global::Func<global::System.IServiceProvider, object>(<FACTORY_METHOD>));
234
+ registrationStatements . Add (
235
+ ExpressionStatement (
236
+ InvocationExpression (
237
+ MemberAccessExpression (
238
+ SyntaxKind . SimpleMemberAccessExpression ,
239
+ IdentifierName ( "global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions" ) ,
240
+ IdentifierName ( registrationMethod ) ) )
241
+ . AddArgumentListArguments (
242
+ Argument ( IdentifierName ( info . Method . ServiceCollectionParameterName ) ) ,
243
+ Argument ( TypeOfExpression ( IdentifierName ( rootServiceTypeName ) ) ) ,
244
+ Argument (
245
+ ObjectCreationExpression (
246
+ GenericName ( Identifier ( "global::System.Func" ) )
247
+ . AddTypeArgumentListArguments (
248
+ IdentifierName ( "global::System.IServiceProvider" ) ,
249
+ PredefinedType ( Token ( SyntaxKind . ObjectKeyword ) ) ) )
250
+ . AddArgumentListArguments ( Argument ( IdentifierName ( factoryMethod ) ) ) ) ) ) ) ;
243
251
244
252
// Register all secondary services, if any
245
253
foreach ( string dependentServiceType in dependentServiceTypeNames )
246
254
{
247
255
// Register the main implementation type:
248
256
//
249
- // global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.<REGISTRATION_METHOD>(<PARAMETER_NAME>, typeof(<DEPENDENT_SERVICE_TYPE>), static services => global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredServices<ROOT_SERVICE_TYPE>(services ));
257
+ // global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.<REGISTRATION_METHOD>(<PARAMETER_NAME>, typeof(<DEPENDENT_SERVICE_TYPE>), new global::System.Func<global::System.IServiceProvider, object>( global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredServices<ROOT_SERVICE_TYPE>));
250
258
registrationStatements . Add (
251
259
ExpressionStatement (
252
260
InvocationExpression (
@@ -258,16 +266,17 @@ public static CompilationUnitSyntax GetSyntax(ServiceCollectionInfo info)
258
266
Argument ( IdentifierName ( info . Method . ServiceCollectionParameterName ) ) ,
259
267
Argument ( TypeOfExpression ( IdentifierName ( dependentServiceType ) ) ) ,
260
268
Argument (
261
- SimpleLambdaExpression ( Parameter ( Identifier ( "services" ) ) )
262
- . AddModifiers ( Token ( SyntaxKind . StaticKeyword ) )
263
- . WithExpressionBody (
264
- InvocationExpression (
265
- MemberAccessExpression (
266
- SyntaxKind . SimpleMemberAccessExpression ,
267
- IdentifierName ( "global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions" ) ,
268
- GenericName ( Identifier ( "GetRequiredService" ) )
269
- . AddTypeArgumentListArguments ( IdentifierName ( rootServiceTypeName ) ) ) )
270
- . AddArgumentListArguments ( Argument ( IdentifierName ( "services" ) ) ) ) ) ) ) ) ;
269
+ ObjectCreationExpression (
270
+ GenericName ( "global::System.Func" )
271
+ . AddTypeArgumentListArguments (
272
+ IdentifierName ( "global::System.IServiceProvider" ) ,
273
+ PredefinedType ( Token ( SyntaxKind . ObjectKeyword ) ) ) )
274
+ . AddArgumentListArguments ( Argument (
275
+ MemberAccessExpression (
276
+ SyntaxKind . SimpleMemberAccessExpression ,
277
+ IdentifierName ( "global::Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions" ) ,
278
+ GenericName ( Identifier ( "GetRequiredService" ) )
279
+ . AddTypeArgumentListArguments ( IdentifierName ( rootServiceTypeName ) ) ) ) ) ) ) ) ) ;
271
280
}
272
281
}
273
282
@@ -294,6 +303,7 @@ public static CompilationUnitSyntax GetSyntax(ServiceCollectionInfo info)
294
303
// [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
295
304
// <MODIFIERS> <RETURN_TYPE> <METHOD_NAME>(global::Microsoft.Extensions.DependencyInjection.IServiceCollection <PARAMETER_NAME>)
296
305
// {
306
+ // <LOCAL_FUNCTIONS>
297
307
// <REGISTRATION_STATEMENTS>
298
308
// }
299
309
MethodDeclarationSyntax configureServicesMethodDeclaration =
@@ -302,6 +312,7 @@ public static CompilationUnitSyntax GetSyntax(ServiceCollectionInfo info)
302
312
. AddParameterListParameters (
303
313
Parameter ( Identifier ( info . Method . ServiceCollectionParameterName ) )
304
314
. WithType ( IdentifierName ( "global::Microsoft.Extensions.DependencyInjection.IServiceCollection" ) ) )
315
+ . AddBodyStatements ( localFunctions . ToArray ( ) )
305
316
. AddBodyStatements ( registrationStatements . ToArray ( ) )
306
317
. AddAttributeLists (
307
318
AttributeList ( SingletonSeparatedList (
0 commit comments