• 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.1
/SRC/Interfaces/Public/Extensions/IServiceCollectionBasicExtensions/Factory.cs
1
/********************************************************************************
2
* Factory.cs                                                                    *
3
*                                                                               *
4
* Author: Denes Solti                                                           *
5
********************************************************************************/
6
using System;
7
using System.Linq.Expressions;
8

9
namespace Solti.Utils.DI.Interfaces
10
{
11
    public static partial class IServiceCollectionBasicExtensions
12
    {
13
        /// <summary>
14
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
15
        /// <code>
16
        /// ScopeFactory.Create
17
        /// (
18
        ///     svcs => svcs.Factory(typeof(IMyService), "serviceName", (scope, type) => new MyService(...), Lifetime.Singleton),
19
        ///     ...
20
        /// )
21
        /// </code>
22
        /// </summary>
23
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
24
        /// <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>
25
        /// <param name="key">The (optional) service key (usually a name).</param>
26
        /// <param name="factoryExpr">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter. Note that the second parameter of the <paramref name="factoryExpr"/> is never generic, even if you registered the factory for an open generic interface.</param>
27
        /// <param name="lifetime">The lifetime of service.</param>
28
        /// <param name="options">Options to be assigned to the service being registered.</param>
29
        /// <remarks>You can register generic services (where the <paramref name="type"/> parameter is an open generic type).</remarks>
30
        public static IServiceCollection Factory(this IServiceCollection self, Type type, object? key, Expression<FactoryDelegate> factoryExpr, LifetimeBase lifetime, ServiceOptions? options = null)
31
        {
1✔
32
            if (self is null)
1✔
33
                throw new ArgumentNullException(nameof(self));
1✔
34

35
            if (type is null)
1✔
36
                throw new ArgumentNullException(nameof(type));
1✔
37

38
            if (factoryExpr is null)
1✔
39
                throw new ArgumentNullException(nameof(factoryExpr));
1✔
40

41
            if (lifetime is null)
1✔
42
                throw new ArgumentNullException(nameof(lifetime));
1✔
43

44
            return self.Register
1✔
45
            (
1✔
46
                //
1✔
47
                // Further validations are done by the created xXxServiceEntry
1✔
48
                //
1✔
49

1✔
50
                lifetime.CreateFrom(type, key, factoryExpr, options ?? ServiceOptions.Default)
1✔
51
            );
1✔
52
        }
1✔
53

54
        /// <summary>
55
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
56
        /// <code>
57
        /// ScopeFactory.Create
58
        /// (
59
        ///     svcs => svcs.Factory(typeof(IMyService), "serviceName", (scope, type) => new MyService(...), Lifetime.Singleton),
60
        ///     ...
61
        /// )
62
        /// </code>
63
        /// </summary>
64
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
65
        /// <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>
66
        /// <param name="key">The (optional) service key (usually a name).</param>
67
        /// <param name="factory">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter. Note that the second parameter of the <paramref name="factory"/> is never generic, even if you registered the factory for an open generic interface.</param>
68
        /// <param name="lifetime">The lifetime of service.</param>
69
        /// <param name="options">Options to be assigned to the service being registered.</param>
70
        /// <remarks>
71
        /// <list type="bullet">
72
        /// <item>You can register generic services (where the <paramref name="type"/> parameter is an open generic type).</item>
73
        /// <item>It's advised to utilize <paramref name="factory"/> expressions (using the <see cref="Factory(IServiceCollection, Type, object?, Expression{FactoryDelegate}, LifetimeBase, ServiceOptions?)"/> method) insted of real factories as they are more performant.</item>
74
        /// </list>
75
        /// </remarks>
76
        public static IServiceCollection Factory(this IServiceCollection self, Type type, object? key, FactoryDelegate factory, LifetimeBase lifetime, ServiceOptions? options = null)
77
            => factory is not null
1✔
78
                ? self.Factory(type, key, factoryExpr: (scope, type) => factory(scope, type), lifetime, options)
1✔
79
                : throw new ArgumentNullException(nameof(factory));
1✔
80

81
        /// <summary>
82
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
83
        /// <code>
84
        /// ScopeFactory.Create
85
        /// (
86
        ///     svcs => svcs.Factory(typeof(IMyService), (scope, type) => new MyService(...), Lifetime.Singleton),
87
        ///     ...
88
        /// )
89
        /// </code>
90
        /// </summary>
91
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
92
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once.</param>
93
        /// <param name="factoryExpr">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter. Note that the second parameter of the <paramref name="factoryExpr"/> is never generic, even if you registered the factory for an open generic interface.</param>
94
        /// <param name="lifetime">The lifetime of service.</param>
95
        /// <param name="options">Options to be assigned to the service being registered.</param>
96
        /// <remarks>You can register generic services (where the <paramref name="type"/> parameter is an open generic type).</remarks>
97
        public static IServiceCollection Factory(this IServiceCollection self, Type type, Expression<FactoryDelegate> factoryExpr, LifetimeBase lifetime, ServiceOptions? options = null) 
98
            => self.Factory(type, null, factoryExpr, lifetime, options);
1✔
99

100
        /// <summary>
101
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
102
        /// <code>
103
        /// ScopeFactory.Create
104
        /// (
105
        ///     svcs => svcs.Factory(typeof(IMyService), (scope, type) => new MyService(...), Lifetime.Singleton),
106
        ///     ...
107
        /// )
108
        /// </code>
109
        /// </summary>
110
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
111
        /// <param name="type">The service type to be registered. It can not be null and can be registered only once.</param>
112
        /// <param name="factory">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter. Note that the second parameter of the <paramref name="factory"/> is never generic, even if you registered the factory for an open generic interface.</param>
113
        /// <param name="lifetime">The lifetime of service.</param>
114
        /// <param name="options">Options to be assigned to the service being registered.</param>
115
        /// <remarks>
116
        /// <list type="bullet">
117
        /// <item>You can register generic services (where the <paramref name="type"/> parameter is an open generic type).</item>
118
        /// <item>It's advised to utilize <paramref name="factory"/> expressions (using the <see cref="Factory(IServiceCollection, Type, Expression{FactoryDelegate}, LifetimeBase, ServiceOptions?)"/> method) insted of real factories as they are more performant.</item>
119
        /// </list>
120
        /// </remarks>
121
        public static IServiceCollection Factory(this IServiceCollection self, Type type, FactoryDelegate factory, LifetimeBase lifetime, ServiceOptions? options = null)
122
            => self.Factory(type, null, factory, lifetime, options);
1✔
123

124
        /// <summary>
125
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
126
        /// <code>
127
        /// ScopeFactory.Create
128
        /// (
129
        ///     svcs => svcs.Factory&lt;IMyService&gt;("serviceName", scope => new MyService(...), Lifetime.Singleton),
130
        ///     ...
131
        /// )
132
        /// </code>
133
        /// </summary>
134
        /// <typeparam name="TType">The service type to be registered. It can be registered only once (with the given <paramref name="key"/>).</typeparam>
135
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
136
        /// <param name="key">The (optional) service key (usually a name).</param>
137
        /// <param name="factoryExpr">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter.</param>
138
        /// <param name="lifetime">The lifetime of service.</param>
139
        /// <param name="options">Options to be assigned to the service being registered.</param>
140
        public static IServiceCollection Factory<TType>(this IServiceCollection self, object? key, Expression<FactoryDelegate<TType>> factoryExpr, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class
141
            => self.Factory(typeof(TType), key, WrapToStandardDelegate(factoryExpr), lifetime, options);
1✔
142

143
        /// <summary>
144
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
145
        /// <code>
146
        /// ScopeFactory.Create
147
        /// (
148
        ///     svcs => svcs.Factory&lt;IMyService&gt;("serviceName", scope => new MyService(...), Lifetime.Singleton),
149
        ///     ...
150
        /// )
151
        /// </code>
152
        /// </summary>
153
        /// <typeparam name="TType">The service type to be registered. It can be registered only once (with the given <paramref name="key"/>).</typeparam>
154
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
155
        /// <param name="key">The (optional) service key (usually a name).</param>
156
        /// <param name="factory">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter.</param>
157
        /// <param name="lifetime">The lifetime of service.</param>
158
        /// <param name="options">Options to be assigned to the service being registered.</param>
159
        /// <remarks>
160
        /// <list type="bullet">
161
        /// <item>You can register generic services (where the <typeparamref name="TType"/> is an open generic type).</item>
162
        /// <item>It's advised to utilize <paramref name="factory"/> expressions (using the <see cref="Factory{TType}(IServiceCollection, object?, Expression{FactoryDelegate{TType}}, LifetimeBase, ServiceOptions?)"/> method) insted of real factories as they are more performant.</item>
163
        /// </list>
164
        /// </remarks>
165
        public static IServiceCollection Factory<TType>(this IServiceCollection self, object? key, FactoryDelegate<TType> factory, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class
166
            => factory is not null
×
167
                ? self.Factory(key, factoryExpr: scope => factory(scope), lifetime, options)
×
168
                : throw new ArgumentNullException(nameof(factory));
×
169

170
        /// <summary>
171
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
172
        /// <code>
173
        /// ScopeFactory.Create
174
        /// (
175
        ///     svcs => svcs.Factory&lt;IMyService&gt;(scope => new MyService(...), Lifetime.Singleton),
176
        ///     ...
177
        /// )
178
        /// </code>
179
        /// </summary>
180
        /// <typeparam name="TType">The service type to be registered. It can be registered only once.</typeparam>
181
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
182
        /// <param name="factoryExpr">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter.</param>
183
        /// <param name="lifetime">The lifetime of service.</param>
184
        /// <param name="options">Options to be assigned to the service being registered.</param>
185
        public static IServiceCollection Factory<TType>(this IServiceCollection self, Expression<FactoryDelegate<TType>> factoryExpr, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class
186
            => self.Factory(typeof(TType), null, WrapToStandardDelegate(factoryExpr), lifetime, options);
1✔
187

188
        /// <summary>
189
        /// Registers a new service factory with the given type. Factories are also services except that the instantiating process is delegated to the caller. Useful if a service has more than one constructor:
190
        /// <code>
191
        /// ScopeFactory.Create
192
        /// (
193
        ///     svcs => svcs.Factory&lt;IMyService&gt;(scope => new MyService(...), Lifetime.Singleton),
194
        ///     ...
195
        /// )
196
        /// </code>
197
        /// </summary>
198
        /// <typeparam name="TType">The service type to be registered. It can be registered only once.</typeparam>
199
        /// <param name="self">The target <see cref="IServiceCollection"/>.</param>
200
        /// <param name="factory">The factory function that is responsible for the instantiation. Its call count depends on the value of the <paramref name="lifetime"/> parameter.</param>
201
        /// <param name="lifetime">The lifetime of service.</param>
202
        /// <param name="options">Options to be assigned to the service being registered.</param>
203
        /// <remarks>
204
        /// <list type="bullet">
205
        /// <item>You can register generic services (where the <typeparamref name="TType"/> is an open generic type).</item>
206
        /// <item>It's advised to utilize <paramref name="factory"/> expressions (using the <see cref="Factory{TType}(IServiceCollection, Expression{FactoryDelegate{TType}}, LifetimeBase, ServiceOptions?)"/> method) insted of real factories as they are more performant.</item>
207
        /// </list>
208
        /// </remarks>
209
        public static IServiceCollection Factory<TType>(this IServiceCollection self, FactoryDelegate<TType> factory, LifetimeBase lifetime, ServiceOptions? options = null) where TType : class
210
            => self.Factory(null, factory, lifetime, options);
×
211

212
        private static Expression<FactoryDelegate> WrapToStandardDelegate<TInterface>(Expression<FactoryDelegate<TInterface>> factoryExpr) where TInterface : class
213
        {
1✔
214
            if (factoryExpr is null)
1✔
215
                throw new ArgumentNullException(nameof(factoryExpr));
×
216

217
            ParameterExpression
1✔
218
                injector = factoryExpr.Parameters[0],
1✔
219
                type = Expression.Parameter(typeof(Type), nameof(type));
1✔
220

221
            return Expression.Lambda<FactoryDelegate>
1✔
222
            (
1✔
223
                factoryExpr.Body,
1✔
224
                injector,
1✔
225
                type
1✔
226
            );
1✔
227
        }
1✔
228
    }
229
}
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

© 2026 Coveralls, Inc