• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Sholtee / injector / 2251

27 Dec 2023 10:00AM UTC coverage: 90.723% (-2.0%) from 92.704%
2251

push

appveyor

Sholtee
Merge branch 'drop_opencover'

2171 of 2393 relevant lines covered (90.72%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.61
/SRC/Interfaces/Public/Extensions/IServiceCollectionBasicExtensions/Service.cs
1
/********************************************************************************
2
* Service.cs                                                                    *
3
*                                                                               *
4
* Author: Denes Solti                                                           *
5
********************************************************************************/
6
using System;
7
using System.Collections.Generic;
8
using System.Linq.Expressions;
9

10
namespace Solti.Utils.DI.Interfaces
11
{
12
    using static Properties.Resources;
13

14
    public static partial class IServiceCollectionBasicExtensions
15
    {
16
        //
17
        // IsAssignableFrom() won't work against generic interfaces
18
        //
19

20
        private static bool Implements(this Type src, Type that)
21
        {
1✔
22
            if (!src.IsClass)
1✔
23
                return false;
1✔
24

25
            if (that.IsInterface)
1✔
26
            {
1✔
27
                if (that.IsGenericTypeDefinition)
1✔
28
                {
1✔
29
                    foreach (Type iface in src.GetInterfaces())
1✔
30
                    {
1✔
31
                        if (iface.IsGenericType && iface.GetGenericTypeDefinition() == that)
×
32
                            return true;
1✔
33
                    }
1✔
34
                }
×
35
                else
36
                {
1✔
37
                    foreach (Type iface in src.GetInterfaces())
1✔
38
                    {
1✔
39
                        if (iface == that)
1✔
40
                            return true;
1✔
41
                    }
1✔
42
                }
1✔
43
            }
1✔
44
            else
45
            {
1✔
46
                if (that.IsGenericTypeDefinition)
1✔
47
                {
1✔
48
                    if (src.IsGenericType && src.GetGenericTypeDefinition() == that)
×
49
                        return true;
1✔
50
                }
×
51
                else
52
                {
1✔
53
                    if (src == that)
1✔
54
                        return true;
1✔
55
                }
×
56
            }
×
57

58
            return src.BaseType?.Implements(that) is true;
×
59
        }
1✔
60

61
        /// <summary>
62
        /// Registers a new named service with the given implementation:
63
        /// <code>
64
        /// ScopeFactory.Create
65
        /// (
66
        ///     svcs => svcs.Service(typeof(IMyService), "serviceName", typeof(MyService), Lifetime.Singleton),
67
        ///     ...
68
        /// )
69
        /// </code>
70
        /// </summary>
71
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
72
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once (with the given <paramref name="key"/>).</param>
73
        /// <param name="key">The (optional) key of the service (usually a name).</param>
74
        /// <param name="implementation">The service implementation to be registered. It can not be null and must implement the service <paramref name="type"/>. Additionally it must have only null or one constructor (that may request another dependecies). In case of multiple constructors you can use the <see cref="IServiceCollectionBasicExtensions.Factory(IServiceCollection, Type, object?, Expression{FactoryDelegate}, LifetimeBase, ServiceOptions?)"/> method or the <see cref="ServiceActivatorAttribute"/>.</param>
75
        /// <param name="lifetime">The lifetime of service.</param>
76
        /// <param name="options">Options to be assigned to the service being registered.</param>
77
        /// <remarks>You may register generic services (where both the interface and the implementation are open generic types). The system will specialize the implementation if you request the concrete service.</remarks> 
78
        public static IServiceCollection Service(this IServiceCollection self, Type type, object? key, Type implementation, LifetimeBase lifetime, ServiceOptions? options = null)
79
        {
1✔
80
            if (self is null)
1✔
81
                throw new ArgumentNullException(nameof(self));
1✔
82

83
            if (type is null)
1✔
84
                throw new ArgumentNullException(nameof(type));
1✔
85

86
            if (implementation is null)
1✔
87
                throw new ArgumentNullException(nameof(implementation));
1✔
88

89
            if (!implementation.Implements(type))     
1✔
90
                throw new ArgumentException(string.Format(Culture, NOT_IMPLEMENTED, type), nameof(type));
1✔
91

92
            if (lifetime is null)
1✔
93
                throw new ArgumentNullException(nameof(lifetime));
1✔
94

95
            return self.Register
1✔
96
            (
1✔
97
                lifetime.CreateFrom(type, key, implementation, options ?? ServiceOptions.Default)
1✔
98
            );
1✔
99
        }
1✔
100

101
        /// <summary>
102
        /// Registers a new named service using arbitrary constructor arguments:
103
        /// <code>
104
        /// ScopeFactory.Create
105
        /// (
106
        ///     svcs => svcs.Service(typeof(IMyService), "serviceName", typeof(MyService), new {ctorParam = ...}, Lifetime.Singleton),
107
        ///     ...
108
        /// )
109
        /// </code>
110
        /// </summary>
111
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
112
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once (with the given <paramref name="key"/>).</param>
113
        /// <param name="key">The (optional) key of the service (usually a name).</param>
114
        /// <param name="implementation">The service implementation to be registered. It can not be null and must implement the service <paramref name="type"/>. Additionally it should have only one public constructor (that may request another dependecies). In case of multiple constructors you can use the <see cref="IServiceCollectionBasicExtensions.Factory(IServiceCollection, Type, Expression{FactoryDelegate}, LifetimeBase, ServiceOptions?)"/> method or the <see cref="ServiceActivatorAttribute"/>.</param>
115
        /// <param name="explicitArgs">Explicit arguments, provided by the user (may be an anonym object or a <see cref="IReadOnlyDictionary{TKey, TValue}"/> where the key is <see cref="string"/> and value is <see cref="object"/>).</param>
116
        /// <param name="lifetime">The lifetime of service.</param>
117
        /// <param name="options">Options to be assigned to the service being registered.</param>
118
        /// <remarks>You may register generic services (where both the interface and the implementation are open generic types). The system will specialize the implementation if you request the concrete service.</remarks> 
119
        public static IServiceCollection Service(this IServiceCollection self, Type type, object? key, Type implementation, object explicitArgs, LifetimeBase lifetime, ServiceOptions? options = null)
120
        {
1✔
121
            if (self is null)
1✔
122
                throw new ArgumentNullException(nameof(self));
1✔
123

124
            if (type is null)
1✔
125
                throw new ArgumentNullException(nameof(type));
1✔
126

127
            if (implementation is null)
1✔
128
                throw new ArgumentNullException(nameof(implementation));
1✔
129

130
            if (!implementation.Implements(type))
1✔
131
                throw new ArgumentException(string.Format(Culture, NOT_IMPLEMENTED, type), nameof(type));
1✔
132

133
            if (explicitArgs is null)
1✔
134
                throw new ArgumentNullException(nameof(explicitArgs));
1✔
135

136
            if (lifetime is null)
1✔
137
                throw new ArgumentNullException(nameof(lifetime));
1✔
138

139
            return self.Register
1✔
140
            (
1✔
141
                lifetime.CreateFrom(type, key, implementation, explicitArgs, options ?? ServiceOptions.Default)
1✔
142
            );
1✔
143
        }
1✔
144

145
        /// <summary>
146
        /// Registers a new named service:
147
        /// <code>
148
        /// ScopeFactory.Create
149
        /// (
150
        ///     svcs => svcs.Service(typeof(MyService), "serviceName", Lifetime.Singleton),
151
        ///     ...
152
        /// )
153
        /// </code>
154
        /// </summary>
155
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
156
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once (with the given <paramref name="key"/>). Must be a class.</param>
157
        /// <param name="key">The (optional) key of the service (usually a name).</param>
158
        /// <param name="lifetime">The lifetime of service.</param>
159
        /// <param name="options">Options to be assigned to the service being registered.</param>
160
        /// <remarks>You may register generic services. The system will specialize the implementation if you request the concrete service.</remarks> 
161
        public static IServiceCollection Service(this IServiceCollection self, Type type, object? key, LifetimeBase lifetime, ServiceOptions? options = null)
162
            => self.Service(type, key, type, lifetime, options);
1✔
163

164
        /// <summary>
165
        /// Registers a new named service using arbitrary constructor arguments:
166
        /// <code>
167
        /// ScopeFactory.Create
168
        /// (
169
        ///     svcs => svcs.Service(typeof(MyService), "serviceName", new {ctorParam = ...}, Lifetime.Singleton),
170
        ///     ...
171
        /// )
172
        /// </code>
173
        /// </summary>
174
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
175
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once (with the given <paramref name="key"/>). Must be a class.</param>
176
        /// <param name="key">The (optional) key of the service (usually a name).</param>
177
        /// <param name="explicitArgs">Explicit arguments, provided by the user (may be an anonym object or a <see cref="IReadOnlyDictionary{TKey, TValue}"/> where the key is <see cref="string"/> and value is <see cref="object"/>).</param>
178
        /// <param name="lifetime">The lifetime of service.</param>
179
        /// <param name="options">Options to be assigned to the service being registered.</param>
180
        /// <remarks>You may register generic services. The system will specialize the implementation if you request the concrete service.</remarks> 
181
        public static IServiceCollection Service(this IServiceCollection self, Type type, object? key, object explicitArgs, LifetimeBase lifetime, ServiceOptions? options = null)
182
            => self.Service(type, key, type, explicitArgs, lifetime, options);
×
183

184
        /// <summary>
185
        /// Registers a new service:
186
        /// <code>
187
        /// ScopeFactory.Create
188
        /// (
189
        ///     svcs => svcs.Service(typeof(MyService), "serviceName", Lifetime.Singleton),
190
        ///     ...
191
        /// )
192
        /// </code>
193
        /// </summary>
194
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
195
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once. Must be a class.</param>
196
        /// <param name="lifetime">The lifetime of service.</param>
197
        /// <param name="options">Options to be assigned to the service being registered.</param>
198
        /// <remarks>You may register generic services. The system will specialize the implementation if you request the concrete service.</remarks> 
199
        public static IServiceCollection Service(this IServiceCollection self, Type type, LifetimeBase lifetime, ServiceOptions? options = null)
200
            => self.Service(type, key: null, type, lifetime, options);
1✔
201

202
        /// <summary>
203
        /// Registers a new service with the given implementation:
204
        /// <code>
205
        /// ScopeFactory.Create
206
        /// (
207
        ///     svcs => svcs.Service(typeof(IMyService), typeof(MyService), Lifetime.Singleton),
208
        ///     ...
209
        /// )
210
        /// </code>
211
        /// </summary>
212
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
213
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once.</param>
214
        /// <param name="implementation">The service implementation to be registered. It can not be null and must implement the service <paramref name="type"/>. Additionally it should have only one constructor (that may request another dependecies). In case of multiple constructors you can use the <see cref="IServiceCollectionBasicExtensions.Factory(IServiceCollection, Type, Expression{FactoryDelegate}, LifetimeBase, ServiceOptions?)"/> method or the <see cref="ServiceActivatorAttribute"/>.</param>
215
        /// <param name="lifetime">The lifetime of service.</param>
216
        /// <param name="options">Options to be assigned to the service being registered.</param>
217
        /// <remarks>You may register generic services (where both the interface and the implementation are open generic types). The system will specialize the implementation if you request the concrete service.</remarks> 
218
        public static IServiceCollection Service(this IServiceCollection self, Type type, Type implementation, LifetimeBase lifetime, ServiceOptions? options = null) 
219
            => self.Service(type, key: null, implementation, lifetime, options);
1✔
220

221
        /// <summary>
222
        /// Registers a new service using arbitrary constructor arguments:
223
        /// <code>
224
        /// ScopeFactory.Create
225
        /// (
226
        ///     svcs => svcs.Service(typeof(IMyService), typeof(MyService), new {ctorParam = ...}, Lifetime.Singleton),
227
        ///     ...
228
        /// )
229
        /// </code>
230
        /// </summary>
231
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
232
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once.</param>
233
        /// <param name="implementation">The service implementation to be registered. It can not be null and must implement the service <paramref name="type"/>. Additionally it should have only one constructor (that may request another dependecies). In case of multiple constructors you can use the <see cref="IServiceCollectionBasicExtensions.Factory(IServiceCollection, Type,Expression{FactoryDelegate}, LifetimeBase, ServiceOptions?)"/> method or the <see cref="ServiceActivatorAttribute"/>.</param>
234
        /// <param name="explicitArgs">Explicit arguments, provided by the user (may be an anonym object or a <see cref="IReadOnlyDictionary{TKey, TValue}"/> where the key is <see cref="string"/> and value is <see cref="object"/>).</param>
235
        /// <param name="lifetime">The lifetime of service.</param>
236
        /// <param name="options">Options to be assigned to the service being registered.</param>
237
        /// <remarks>You may register generic services (where both the interface and the implementation are open generic types). The system will specialize the implementation if you request the concrete service.</remarks> 
238
        public static IServiceCollection Service(this IServiceCollection self, Type type, Type implementation, object explicitArgs, LifetimeBase lifetime, ServiceOptions? options = null)
239
            => self.Service(type, null, implementation, explicitArgs, lifetime, options);
1✔
240

241
        /// <summary>
242
        /// Registers a new service with the given implementation:
243
        /// <code>
244
        /// ScopeFactory.Create
245
        /// (
246
        ///     svcs => svcs.Service&lt;IMyService, MyService&gt;(Lifetime.Singleton),
247
        ///     ...
248
        /// )
249
        /// </code>
250
        /// </summary>
251
        /// <typeparam name="TType">The service type to be registered. It can be registered only once.</typeparam>
252
        /// <typeparam name="TImplementation">The service implementation to be registered. It must implement the service <typeparamref name="TType"/> and should have only one public constructor (that may request another dependecies). In case of multiple constructors you can use the <see cref="IServiceCollectionBasicExtensions.Factory{TType}(IServiceCollection, Expression{FactoryDelegate{TType}}, LifetimeBase, ServiceOptions?)"/> method or the <see cref="ServiceActivatorAttribute"/>.</typeparam>
253
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
254
        /// <param name="lifetime">The lifetime of service.</param>
255
        /// <param name="options">Options to be assigned to the service being registered.</param>
256
        public static IServiceCollection Service<TType, TImplementation>(this IServiceCollection self, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class where TImplementation: TType 
257
            => self.Service(typeof(TType), typeof(TImplementation), lifetime, options);
1✔
258

259
        /// <summary>
260
        /// Registers a new named service with the given implementation:
261
        /// <code>
262
        /// ScopeFactory.Create
263
        /// (
264
        ///     svcs => svcs.Service&lt;IMyService, MyService&gt;("serviceName", Lifetime.Singleton),
265
        ///     ...
266
        /// )
267
        /// </code>
268
        /// </summary>
269
        /// <typeparam name="TType">The service type to be registered. It can be registered only once (with the given <paramref name="key"/>).</typeparam>
270
        /// <typeparam name="TImplementation">The service implementation to be registered. It must implement the service <typeparamref name="TType"/> and must have only null or one constructor (that may request another dependecies). In case of multiple constructors you can use the <see cref="IServiceCollectionBasicExtensions.Factory{TType}(IServiceCollection, Expression{FactoryDelegate{TType}}, LifetimeBase, ServiceOptions?)"/> method or the <see cref="ServiceActivatorAttribute"/>.</typeparam>
271
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
272
        /// <param name="key">The (optional) key of the service (usually a name).</param>
273
        /// <param name="lifetime">The lifetime of service.</param>
274
        /// <param name="options">Options to be assigned to the service being registered.</param>
275
        public static IServiceCollection Service<TType, TImplementation>(this IServiceCollection self, object? key, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class where TImplementation : TType 
276
            => self.Service(typeof(TType), key, typeof(TImplementation), lifetime, options);
1✔
277

278
        /// <summary>
279
        /// Registers a new named service using arbitrary constructor arguments:
280
        /// <code>
281
        /// ScopeFactory.Create
282
        /// (
283
        ///     svcs => svcs.Service&lt;IMyService, MyService&gt;("serviceName", new {ctorParam = ...}, Lifetime.Singleton),
284
        ///     ...
285
        /// )
286
        /// </code>
287
        /// </summary>
288
        /// <typeparam name="TType">The service type to be registered. It can be registered only once (with the given <paramref name="key"/>).</typeparam>
289
        /// <typeparam name="TImplementation">The service implementation to be registered. It must implement the service <typeparamref name="TType"/> and must have only null or one constructor (that may request another dependecies). In case of multiple constructors you can use the <see cref="IServiceCollectionBasicExtensions.Factory{TType}(IServiceCollection, Expression{FactoryDelegate{TType}}, LifetimeBase, ServiceOptions?)"/> method or the <see cref="ServiceActivatorAttribute"/>.</typeparam>
290
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
291
        /// <param name="key">The (optional) key of the service (usually a name).</param>
292
        /// <param name="explicitArgs">Explicit arguments, provided by the user (may be an anonym object or a <see cref="IReadOnlyDictionary{TKey, TValue}"/> where the key is <see cref="string"/> and value is <see cref="object"/>).</param>
293
        /// <param name="lifetime">The lifetime of service.</param>
294
        /// <param name="options">Options to be assigned to the service being registered.</param>
295
        public static IServiceCollection Service<TType, TImplementation>(this IServiceCollection self, object? key, object explicitArgs, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class where TImplementation : TType
296
            => self.Service(typeof(TType), key, typeof(TImplementation), explicitArgs, lifetime, options);
1✔
297

298
        /// <summary>
299
        /// Registers a new named service using arbitrary constructor arguments:
300
        /// <code>
301
        /// ScopeFactory.Create
302
        /// (
303
        ///     svcs => svcs.Service&lt;MyService&gt;("serviceName", new {ctorParam = ...}, Lifetime.Singleton),
304
        ///     ...
305
        /// )
306
        /// </code>
307
        /// </summary>
308
        /// <typeparam name="TType">The service type to be registered. It can be registered only once (with the given <paramref name="key"/>). Must be a class.</typeparam>
309
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
310
        /// <param name="key">The (optional) key of the service (usually a name).</param>
311
        /// <param name="explicitArgs">Explicit arguments, provided by the user (may be an anonym object or a <see cref="IReadOnlyDictionary{TKey, TValue}"/> where the key is <see cref="string"/> and value is <see cref="object"/>).</param>
312
        /// <param name="lifetime">The lifetime of service.</param>
313
        /// <param name="options">Options to be assigned to the service being registered.</param>
314
        public static IServiceCollection Service<TType>(this IServiceCollection self, object? key, object explicitArgs, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class
315
            => self.Service(typeof(TType), key, explicitArgs, lifetime, options);
×
316

317
        /// <summary>
318
        /// Registers a new named service:
319
        /// <code>
320
        /// ScopeFactory.Create
321
        /// (
322
        ///     svcs => svcs.Service&lt;MyService&gt;("serviceName", Lifetime.Singleton),
323
        ///     ...
324
        /// )
325
        /// </code>
326
        /// </summary>
327
        /// <typeparam name="TType">The service type to be registered. It can be registered only once (with the given <paramref name="key"/>). Must be a class.</typeparam>
328
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
329
        /// <param name="key">The (optional) key of the service (usually a name).</param>
330
        /// <param name="lifetime">The lifetime of service.</param>
331
        /// <param name="options">Options to be assigned to the service being registered.</param>
332
        public static IServiceCollection Service<TType>(this IServiceCollection self, object? key, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class
333
            => self.Service(typeof(TType), key, lifetime, options);
1✔
334

335
        /// <summary>
336
        /// Registers a new service:
337
        /// <code>
338
        /// ScopeFactory.Create
339
        /// (
340
        ///     svcs => svcs.Service&lt;MyService&gt;(new {ctorParam = ...}, Lifetime.Singleton),
341
        ///     ...
342
        /// )
343
        /// </code>
344
        /// </summary>
345
        /// <typeparam name="TType">The service type to be registered. It can be registered only once. Must be a class.</typeparam>
346
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
347
        /// <param name="lifetime">The lifetime of service.</param>
348
        /// <param name="options">Options to be assigned to the service being registered.</param>
349
        public static IServiceCollection Service<TType>(this IServiceCollection self, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class
350
            => self.Service<TType>(key: null, lifetime, options);
1✔
351
    }
352
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc