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

Sholtee / injector / 2221

01 Dec 2023 07:49AM UTC coverage: 93.276% (-0.6%) from 93.921%
2221

push

appveyor

Sholtee
Merge branch 'v10'

1415 of 1517 relevant lines covered (93.28%)

3.69 hits per line

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

92.0
/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
        {
4✔
32
            if (self is null)
4✔
33
                throw new ArgumentNullException(nameof(self));
4✔
34

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

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

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

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

50
                lifetime.CreateFrom(type, key, factoryExpr, options ?? ServiceOptions.Default)
51
            );
52
        }
4✔
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
4✔
78
                ? self.Factory(type, key, factoryExpr: (scope, type) => factory(scope, type), lifetime, options)
79
                : throw new ArgumentNullException(nameof(factory));
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);
4✔
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);
4✔
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);
4✔
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
4✔
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);
4✔
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
        {
4✔
214
            if (factoryExpr is null)
4✔
215
                throw new ArgumentNullException(nameof(factoryExpr));
×
216

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

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